点分治学习笔记(Updating)

这里就不讲点分治的原理以及一些注意事项了,只讲几道例题吧(懒

[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

猜你喜欢

转载自www.cnblogs.com/zhenglw/p/10658210.html
今日推荐