这里就不讲点分治的原理以及一些注意事项了,只讲几道例题吧(懒
[T1 Luogu3806]【模板】点分治1
给定一棵有n个点的树
询问树上距离为k的点对是否存在。
一看标题就是点分治了嘛...
这是之前在机房打的
对每个路径长度进行标记即可,考虑到重复标记,容斥原理搞一下对于子树的答案贡献权值-1即可(就是更新的时候把新增贡献改为-1)
#include<cstdio> #include<queue> #include<iostream> #include<cstring> #define R register using namespace std; inline int read(){ int ans=0,f=1;char chr=getchar(); while(!isdigit(chr)){if(chr=='-') f=-1;chr=getchar();} while(isdigit(chr)){ans=(ans<<3)+(ans<<1)+chr-48;chr=getchar();} return ans*f; }const int M=100005<<1; int head[M],ver[M],nxt[M],val[M],tot,n,m,x,root,sz[M],mx[M],vis[M],ANS[M],p,a[M],dis[M],s; inline void add(int x,int y,int z){ver[++tot]=y;val[tot]=z;nxt[tot]=head[x];head[x]=tot;} void Find_Gf(int x,int fa){//找根 sz[x]=1;mx[x]=0; for(R int i=head[x];i;i=nxt[i]) if(ver[i]!=fa&&!vis[ver[i]]) Find_Gf(ver[i],x),sz[x]+=sz[ver[i]],mx[x]=max(mx[x],sz[ver[i]]); mx[x]=max(s-sz[x],mx[x]); if(mx[x]<mx[root]) root=x; } void dfs(int x,int len,int fa){//找路径 dis[++p]=a[x]; for(R int i=head[x];i;i=nxt[i]) if(ver[i]!=fa&&!vis[ver[i]]) a[ver[i]]=len+val[i],dfs(ver[i],a[ver[i]],x); } void Calc(int x,int len,int w){//标记路径 p=0,a[x]=len,dfs(x,len,0); for(R int i=1;i<=p;++i) for(R int j=1;j<=p;++j) if(i!=j) ANS[dis[i]+dis[j]]+=w; } void Solve(int x){//点分治 Calc(x,0,1),vis[x]=1; for(R int i=head[x];i;i=nxt[i]) if(!vis[ver[i]]) Calc(ver[i],val[i],-1),s=sz[x],root=0,mx[0]=n,Find_Gf(ver[i],x),Solve(root); }int main(){ n=read();m=read(); for(R int i=1,a,b,z;i<n;++i) a=read(),b=read(),z=read(),add(a,b,z),add(b,a,z); s=n,mx[0]=n,root=0; Find_Gf(1,0),Solve(root); while(m--) puts(ANS[x=read()]?"AYE":"NAY"); return 0; }
持续更新ing