上午学习了点分治,写了1个半小时终于写出一个代码--poj1741,可以说是个模板题。
分治:对于每个儿子找出重心,分别处理
注意:1.每次处理一个重心后,ans减去对它儿子的处理
原因:因为统计方法没管是否在同一棵树上,所以答案有重复
2.每次寻找新的重心时,树的大小变化,重新计算大小,否则TLE
CODE:
#include<cstdio> #include<iostream> #include<cstring> #include<vector> #include<algorithm> #include<cmath> #define ll long long #define inf 2147483647 #define N 10005 using namespace std; int n,k,dis[N],f[N],siz[N],vis[N],rt,ans,size; struct node{ int v,w; }; vector<int>d; vector<node>g[N]; void getrt(int u,int fa){ siz[u]=1;f[u]=0; for(int i=0;i<g[u].size();i++){ int v=g[u][i].v; if(vis[v]||v==fa)continue; getrt(v,u); siz[u]+=siz[v]; f[u]=max(f[u],siz[v]); } f[u]=max(f[u],size-siz[u]); if(f[u]<f[rt])rt=u; } void getdis(int u,int fa){ d.push_back(dis[u]); for(int i=0;i<g[u].size();i++){ int v=g[u][i].v,w=g[u][i].w; if(vis[v]||v==fa)continue; dis[v]=dis[u]+w; getdis(v,u); } } int cal(int u,int fir){ int ret=0; d.clear(); dis[u]=fir; getdis(u,0); int l=0,r=d.size()-1; sort(d.begin(),d.end()); while(l<r){ while(d[l]+d[r]>k&&l<r)r--; ret+=r-l;l++; } return ret; } void work(int u){ ans+=cal(u,0); vis[u]=1; for(int i=0;i<g[u].size();i++){ int v=g[u][i].v,w=g[u][i].w; if(vis[v])continue; ans-=cal(v,w); f[0]=size=siz[u]; getrt(v,rt=0); work(rt); } } int main(){ while(1){ scanf("%d%d",&n,&k); if(!n)break; for(int i=1;i<=n;i++) g[i].clear(),vis[i]=0; int u,v,w; for(int i=1;i<n;i++) scanf("%d%d%d",&u,&v,&w), g[v].push_back(node{u,w}), g[u].push_back(node{v,w}); ans=0;f[0]=size=n; getrt(1,rt=0); work(rt); printf("%d ",ans); } return 0; }