BZOJ1468 Tree
题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1468
一道水题,好久没有打点分治了有点手生。
犯了傻,打错了 addedge 调了1h。
基本思路就是按层分治,不超过 O(logn) 层,每一层 O(n) 或者 O(logn) 根据主定理 T(n) = T(n/2) + O(nlogn)
复杂度 O(nlog^2n) 。
此题在统计路径时还要注意容斥,要减去多余的路径。(具体看紫书即可)
#include <cstdio> #include <cstring> #include <algorithm> #define N 50010 #define LL long long using namespace std; struct edge{ int x,to,v; }E[N<<1]; int n,g[N],K,totE,ansv; inline void addedge(int x,int y,int v){ E[++totE]=(edge){y,g[x],v}; g[x]=totE; E[++totE]=(edge){x,g[y],v}; g[y]=totE; } #define p E[i].x namespace Tree_Dc{ int siz[N],root,f[N],totn,a[N],d[N],tot; bool v[N]; void Find_Hea(int x,int ft){ siz[x]=1; f[x]=0; for(int i=g[x];i;i=E[i].to) if(ft!=p&&!v[p]){ Find_Hea(p,x); siz[x]+=siz[p]; f[x]=max(f[x],siz[p]); } f[x]=max(f[x],totn-siz[x]); if(!root||f[x]<f[root]) root=x; } inline int Root(int x){ root=0; totn=siz[x]; Find_Hea(x,x); return root; } void dfs(int x,int ft){ a[++tot]=d[x]; for(int i=g[x];i;i=E[i].to) if(!v[p]&&p!=ft){ d[p]=d[x]+E[i].v; dfs(p,x); } } inline int count_path(int x,int v){ d[x]=v; tot=0; dfs(x,0); sort(a+1,a+tot+1); int ans=0,tmp=1; for(int i=2;i<=tot;i++){ while(tmp<i&&a[i]+a[tmp+1]<=K) tmp++; while(tmp&&a[i]+a[tmp]>K) tmp--; ans+=min(tmp,i-1); } return ans; } void DC(int x){ int tmp=ansv; ansv+=count_path(x,0); v[x]=1; for(int i=g[x];i;i=E[i].to) if(!v[p]){ ansv-=count_path(p,E[i].v); DC(Root(p)); } } } int main(){ freopen("test.in","r",stdin); scanf("%d",&n); for(int i=1,x,y,v;i<n;i++){ scanf("%d%d%d",&x,&y,&v); addedge(x,y,v); } scanf("%d",&K); Tree_Dc::siz[1]=n; Tree_Dc::DC(Tree_Dc::Root(1)); printf("%d\n",ansv); return 0; }