BZOJ 1468——tree
BZOJ 1468——tree
点分治思想,处理一些树上路径问题中的高效算法。
重心——作用是可以优化时间复杂度,使递归的层数最少。
重心就是以某个点为根且这个点的子树最大值是最小的。
找重心的基本思路:
dfs求得每一个点的最大子树Maxsize,用数组记录下来,
判断这个值是否比当前根的Maxsize小。每次找重心都会更新size数组。
inline void getroot(int x,int fa){ size[x]=1;Maxsize[x]=0; for(int i=head[x];i;i=e[i].next){ if(!vis[e[i].to]&&e[i].to!=fa){ getroot(e[i].to,x);size[x]+=size[e[i].to];Maxsize[x]=max(Maxsize[x],size[e[i].to]); } } Maxsize[x]=max(Maxsize[x],temp-size[x]); if(Maxsize[x]<Maxsize[root]) root=x; }
找重心
处理计算通过根节点的路径。
递归处理每个根节点的子节点。重复以上操作
Notice:在计算通过某个点的个数时,还需要减去一些不符合题意的边,
就是没有通过当前节点的边,才不会重复计算。
每次计算完一个节点后,把该节点删去,即用vis标记。
此外,用一个deep数组来储存以X节点为根时,该节点的子树中到根的距离。(代码中的deep[0]只是一个计数变量而已)
#include<cstdio> #include<algorithm> #define maxn 40010 using namespace std; struct LINK{ int to,next,v; }e[maxn*2]; int deep[maxn],Distance[maxn],Maxsize[maxn],size[maxn],temp,tot,head[maxn],vis[maxn],root,k,ans; inline char Getchar(){ static char BUF[16384],*S=BUF,*T=BUF; return(S==T)&&(T=(S=BUF)+fread(BUF,1,16384,stdin),S==T)?EOF:*S++; } inline int read(){ int w=0;char c=Getchar(); while(c<'0'||c>'9') c=Getchar(); while(c>='0'&&c<='9'){ w=w*10+c-48; c=Getchar(); } return w; } inline void add(int x,int y,int w){ tot++; e[tot].to=y; e[tot].next=head[x]; e[tot].v=w; head[x]=tot; } inline void getroot(int x,int fa){ size[x]=1;Maxsize[x]=0; for(int i=head[x];i;i=e[i].next){ if(!vis[e[i].to]&&e[i].to!=fa){ getroot(e[i].to,x);size[x]+=size[e[i].to];Maxsize[x]=max(Maxsize[x],size[e[i].to]); } } Maxsize[x]=max(Maxsize[x],temp-size[x]); if(Maxsize[x]<Maxsize[root]) root=x; } inline void getdeep(int x,int fa){ deep[++deep[0]]=Distance[x]; for(int i=head[x];i;i=e[i].next){ if(!vis[e[i].to]&&e[i].to!=fa){ Distance[e[i].to]=Distance[x]+e[i].v;getdeep(e[i].to,x); } } } inline int answer(int x,int w){ int ans=0,l=1,r; Distance[x]=w;deep[0]=0;getdeep(x,0); sort(deep+1,deep+deep[0]+1); r=deep[0]; while(l<r){ if((deep[l]+deep[r])<=k) ans+=r-l,l++; else r--; } return ans; } inline void solve(int x){ ans+=answer(x,0);vis[x]=1; for(int i=head[x];i;i=e[i].next){ if(!vis[e[i].to]){ ans-=answer(e[i].to,e[i].v);temp=size[e[i].to];root=0; getroot(e[i].to,0);solve(root); } } } int main(){ int n,i,x,y,v; n=read(); for(i=1;i<n;i++){ x=read();y=read();v=read(); add(x,y,v);add(y,x,v); } k=read();Maxsize[0]=n+1; temp=n; getroot(1,0);solve(root); printf("%d",ans); }