日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

P4178 Tree

發(fā)布時(shí)間:2023/12/3 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 P4178 Tree 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

P4178 Tree

題意:

給定一棵 n 個(gè)節(jié)點(diǎn)的樹,每條邊有邊權(quán),求出樹上兩點(diǎn)距離小于等于 k 的點(diǎn)對(duì)數(shù)量。

題解:

點(diǎn)分治的模板題是求等于K的路徑條數(shù)
本題是求小于等于K的路徑條數(shù),我們只需要改變統(tǒng)計(jì)答案即可
原本統(tǒng)計(jì)答案是對(duì)一個(gè)路勁長(zhǎng)度len,判斷K-len在之前的子樹中出現(xiàn)多少次,用f數(shù)組來(lái)記錄,直接查看f[k-len]等于多少即可
現(xiàn)在統(tǒng)計(jì)答案是對(duì)一個(gè)路徑長(zhǎng)度len,判斷小于等于K-len的數(shù)在之前的子樹中出現(xiàn)多少次,統(tǒng)計(jì)區(qū)間數(shù)量,我們可以用樹狀數(shù)組來(lái)實(shí)現(xiàn),對(duì)于每個(gè)len我們插入數(shù)組f[]其中,然后求1~K-len的區(qū)間查詢

代碼:

詳細(xì)看代碼

#include<bits/stdc++.h> #define MAXN 40005 #define MAXK 20005 using namespace std;int N,K;struct edge{int v,w;edge(int v=0, int w=0):v(v), w(w){} };vector<edge> adj[MAXN];// int fw[MAXK]; int lbt(int x){return x & (-x); } int getsum(int x){int ans = 0;for(;x>0;x-=lbt(x)){ans += fw[x];}return ans; }void change(int x, int dv){for(;x<=K;x+=lbt(x)){fw[x] += dv;} }// int sz[MAXN]; bool vis[MAXN]; int rt; void dfs_rt(int u, int fa, int tot){//O(tot)求根 sz[u] = 1;int v, n = 0;for(int k=0;k<adj[u].size();k++){v = adj[u][k].v;if(v==fa || vis[v]) continue;dfs_rt(v, u, tot);sz[u] += sz[v];n = max(n, sz[v]);}n = max(n, tot-sz[u]);if(n*2 <= tot) rt = u; }void dfs_sz(int u, int fa){//O(tot)求子樹sz[u] = 1;int v, n = 0;for(int k=0;k<adj[u].size();k++){v = adj[u][k].v;if(v==fa || vis[v]) continue;dfs_sz(v, u);sz[u] += sz[v];} }int d[MAXN], cnt = 0; void dfs_dis(int u, int fa, int dis){//O(tot)d[++cnt] = dis;//記錄距離 int v,w;for(int k=0;k<adj[u].size();k++){v = adj[u][k].v;w = adj[u][k].w;if(v==fa || vis[v]) continue;dfs_dis(v, u, dis + w);} }void dfs_clear(int u, int fa, int dis){//O(tot)清零 if(dis) change(dis, -1);int v,w;for(int k=0;k<adj[u].size();k++){v = adj[u][k].v;w = adj[u][k].w;if(v==fa || vis[v]) continue;dfs_clear(v, u, dis + w);} }int work(int u, int tot){ dfs_rt(u, 0, tot);u = rt;dfs_sz(u, 0);vis[u] = 1;int v,w;//solve/*求出每個(gè)點(diǎn)到根節(jié)點(diǎn)的距離,然后記錄到數(shù)組d然后對(duì)于d[i],查詢0~K-d[i]區(qū)間大小,用樹狀數(shù)組實(shí)現(xiàn) 如果d[i]<=K,那么d[i]本身也符合條件 將數(shù)組d插入到樹狀數(shù)組當(dāng)以一個(gè)點(diǎn)為根的一輪結(jié)束時(shí)記得情況數(shù)組樹狀數(shù)組 */ int ans = 0;for(int k=0;k<adj[u].size();k++){v = adj[u][k].v;w = adj[u][k].w;if(vis[v]) continue;cnt = 0;dfs_dis(v, u, w);for(int i=1;i<=cnt;i++){if(d[i] <= K) ++ans;ans += getsum(max(0,K-d[i]));}for(int i=1;i<=cnt;i++){change(d[i], +1);}}dfs_clear(u,0,0);//手動(dòng)清空 //for(int k=0;k<adj[u].size();k++){v = adj[u][k].v;//w = adj[u][k].w;if(vis[v]) continue;ans += work(v,sz[v]);} return ans; }int main(){cin>>N;int u,v,w;for(int i=1;i<N;i++){cin>>u>>v>>w;adj[u].push_back(edge(v,w));adj[v].push_back(edge(u,w));}cin>>K;cout<<work(1, N)<<endl;return 0; }

總結(jié)

以上是生活随笔為你收集整理的P4178 Tree的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。