zoukankan      html  css  js  c++  java
  • 模板·点分治(luogu P3806)

    [模板]洛谷·点分治


    1、求树的重心

    树的重心:若A点的子树中最大的子树的size[] 最小时,A为该树的中心

    步骤:

    • 所需变量:siz[x] 表示 x 的子树大小(含自己),msz[x] 表示 其子树中最大的子树的大小,sum表示当前子树所有节点个数,root表示当前子树根节点
    • 处理出siz[x],msz[x]
    • 按最大子树最小的标准处理出root
    inline void GetRoot(int x,int fa){
        siz[x]=1;msz[x]=0;siz[x]//表示 x 的子树大小(含自己),msz[x] 表示其子树中最大的子树的大小   
        for(Rint i=beg[x];i;i=nex[i]){
            int y=to[i];
            if(y==fa||vis[y])continue;
            GetRoot(y,x);
            siz[x]+=siz[y];
            msz[x]=max(msz[x],siz[y]);
        }
        msz[x]=max(msz[x],sum-siz[x]);//按最大子树最小的标准处理出root   
        if(msz[x]<msz[root])root=x;
    }
    inline void GR_Init(int x,int fa){
        sum=siz[x];//sum表示当前子树所有节点个数  
        root=0;//root表示当前子树根节点  
        GetRoot(x,fa);
    }
    

    2、分而治之

    步骤:

    • 处理出经过这个节点的所有所求贡献
    • 减去其子树内不需要被计算但却被计算的贡献
    • 对其子树继续分治
    inline void Point_Divide(int x){
        vis[x]=1;
        Calc(x,0,1);//处理出经过这个节点的所有所求贡献
        for(Rint i=beg[x];i;i=nex[i]){
            int y=to[i];
            if(vis[y])continue;
            Calc(y,w[i],-1);//减去其子树内不需要被计算但却被计算的贡献
            GR_Init(y,x);
            Point_Divide(root);//对其子树继续分治
        }
    }
    

    3、洛谷P3806点分治模板AC代码

    #include<algorithm>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<cstdio>
    #define Rint register int
    #define mem(a,b) memset(a,(b),sizeof(a))
    using namespace std;
    typedef long long LL;
    template<typename T>inline void read(T &x){
        x=0;T w=1,ch=getchar();
        while(!isdigit(ch)&&ch!='-')ch=getchar();
        if(ch=='-')w=-1,ch=getchar();
        while(isdigit(ch))x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar();
        x=x*w;
    }
    inline void File(){
        freopen("fuck.in","r",stdin);
        freopen("fuck.out","w",stdout);
    }
    
    const int maxn=100000+10,inf=0x7f7f7f7f;
    int n,m;
    int e,beg[maxn],nex[maxn<<1],to[maxn<<1],w[maxn<<1];
    int dis[maxn],siz[maxn],dep[maxn],msz[maxn];
    int sum,root,cnt;
    int ask[maxn],ans[maxn];
    bool vis[maxn];
    
    inline void add(int x,int y,int z){
        to[++e]=y;
        nex[e]=beg[x];
        beg[x]=e;
        w[e]=z;
    }
    inline void GetRoot(int x,int fa){
        siz[x]=1;msz[x]=0;//siz[x]表示 x 的子树大小(含自己),msz[x] 表示其子树中最大的子树的大小   
        for(Rint i=beg[x];i;i=nex[i]){
            int y=to[i];
            if(y==fa||vis[y])continue;
            GetRoot(y,x);
            siz[x]+=siz[y];
            msz[x]=max(msz[x],siz[y]);
        }
        msz[x]=max(msz[x],sum-siz[x]);//按最大子树最小的标准处理出root   
        if(msz[x]<msz[root])root=x;
    }
    inline void GR_Init(int x,int fa){
        sum=siz[x];//sum表示当前子树所有节点个数  
        root=0;//root表示当前子树根节点  
        GetRoot(x,fa);
    }
    inline void GetDeep(int x,int fa){//处理深度
        dis[++cnt]=dep[x];
        for(Rint i=beg[x];i;i=nex[i]){
            int y=to[i];
            if(vis[y]||y==fa)continue;
            dep[y]=dep[x]+w[i];
            GetDeep(y,x);
        }
    }
    inline void GD_Init(int x,int val){
        cnt=0;
        dep[x]=val;
        GetDeep(x,0);
    }
    inline void Calc(int x,int val,int mrk){//计算贡献
        GD_Init(x,val);
        sort(dis+1,dis+cnt+1);
        for(Rint i=1;i<=m;i++){
            for(Rint l=1,r=cnt;l<r;l++){
                while(l<r&&dis[l]+dis[r]>=ask[i]){
                    if(dis[l]+dis[r]==ask[i])ans[i]+=mrk;
                    r--;
                }
            }
        }
    }
    inline void Point_Divide(int x){
        vis[x]=1;
        Calc(x,0,1);//处理出经过这个节点的所有所求贡献
        for(Rint i=beg[x];i;i=nex[i]){
            int y=to[i];
            if(vis[y])continue;
            Calc(y,w[i],-1);//减去其子树内不需要被计算但却被计算的贡献
            GR_Init(y,x);
            Point_Divide(root);//对其子树继续分治
        }
    }
    
    int main(){
        //File();
        read(n);read(m);
        for(Rint i=1;i<n;i++){
            int x,y,z;read(x);read(y);read(z);
            add(x,y,z);add(y,x,z);
        }
        for(Rint i=1;i<=m;i++)read(ask[i]);
        msz[0]=inf;sum=n;GetRoot(1,0);
        Point_Divide(root);
        for(Rint i=1;i<=m;i++){
            if(ans[i])printf("AYE
    ");
            else printf("NAY
    ");
        }
        return 0;
    }
    
  • 相关阅读:
    全面了解 NOSQL
    金融业容灾技术分析
    银行业务知识(转)
    结合工作的业务连续性实践
    金融企业架构
    window 下拉取github项目失败 (Permission denied (publickey))
    vsftpd 配置文件
    nginx下配置虚拟主机
    linux 下安装ftp 并远程连接
    find_in_set
  • 原文地址:https://www.cnblogs.com/chinhhh/p/8734399.html
Copyright © 2011-2022 走看看