1. 程式人生 > >poj1741 Tree(點分治)

poj1741 Tree(點分治)

main size std sync pac init ems style cout

題目鏈接:http://poj.org/problem?id=1741

題意:求樹上兩點之間距離小於等於k的點對的數量

思路:點分治模板題,推薦一篇講的非常好的博客:https://blog.csdn.net/qq_39553725/article/details/77542223

實現代碼:

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
#define lson l,m,rt<<1
#define
inf 0x7fffffff #define rson m+1,r,rt<<1|1 #define mid int m = (l + r) >> 1 const int M = 1e5+10; struct node{ int to,w,next; }e[M<<2]; int n,m; int vis[M],dis[M],d[M],siz[M],f[M],cnt,head[M],sum,root,k,ans; void init(){ cnt = 0; ans = 0; memset(head,0,sizeof
(head)); memset(vis,0,sizeof(vis)); } void add(int u,int v,int w){ e[++cnt].to=v;e[cnt].w=w;e[cnt].next=head[u];head[u]=cnt; } void get_root(int u,int fa){ siz[u] = 1; f[u] = 0; for(int i = head[u];i;i=e[i].next){ int v = e[i].to; if(v!=fa&&!vis[v]){ get_root(v,u); siz[u]
+= siz[v]; f[u] = max(f[u],siz[v]); } } // cout<<"sum: "<<sum-siz[v]<<endl f[u] = max(f[u],sum - siz[u]); if(f[u] < f[root]) root = u; return ; } void get_dis(int u,int fa){ dis[++dis[0]] = d[u]; for(int i = head[u];i;i = e[i].next){ int v = e[i].to; if(v != fa&& !vis[v]){ d[v] = d[u] + e[i].w; get_dis(v,u); } } return; } int cal(int u,int c){ d[u] = c; dis[0] = 0; get_dis(u,0); sort(dis+1,dis+dis[0]+1); int l = 1,r = dis[0],sum = 0; while(l < r){ if(dis[l] + dis[r] <= k){ sum+=r-l; l ++; } else r--; } return sum; } void solve(int u){ ans += cal(u,0); vis[u] = 1; for(int i = head[u];i;i = e[i].next){ int v = e[i].to; if(!vis[v]){ ans -= cal(v,e[i].w); sum = siz[v] ; root = 0; get_root(v,0); solve(root); } } } int main() { int u,v,w; ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); while(cin>>n>>k){ if(n==0&&m==0) break; init(); for(int i = 1;i <= n-1;i ++){ cin>>u>>v>>w; add(u,v,w); add(v,u,w); } f[0] = inf; sum = n; root = 0; get_root(1,0); solve(root); cout<<ans<<endl; } return 0; }

poj1741 Tree(點分治)