• 2019沈阳网路赛 D. Fish eating fruit (点分治)


    传送门

    题意

    给一颗树,统计出树上 (\%3=0,1,2) 的路径总和分别是多少

    题解

    不知道为什么点分治的题 (n) 一般都给 (10^4)
    这个题用点分治是很好做的,统计对三取余分别为 (0,1,2) 的路径的条数和总长,然后累加答案就行

    代码

    //尝试淀粉质
    #include <bits/stdc++.h>
    typedef long long LL;
    using namespace std;
    const int MAXN=1e4+10;
    const int mod=1e9+7;
    int n,head[MAXN],to[MAXN*2],nxt[MAXN*2],val[MAXN*2],tot;
    int siz[MAXN],maxp[MAXN],sum,rt,dead[MAXN],cnt,dis[MAXN];
    LL ans[3],dissum[3],disnum[3];
    
    void add(int u,int v,int w){
        to[++tot]=v;val[tot]=w;nxt[tot]=head[u];head[u]=tot;
    }
    
    void getrt(int u,int fa){
        siz[u]=1;maxp[u]=0;
        for(int i=head[u];i;i=nxt[i]){
            if(to[i]==fa||dead[to[i]]) continue;
            getrt(to[i],u);
            siz[u]+=siz[to[i]];
            maxp[u]=max(maxp[u],siz[to[i]]);
        }
        maxp[u]=max(maxp[u],sum-siz[u]);
        if(maxp[u]<maxp[rt]) rt=u;
    }
    
    void getdis(int u,int fa,int w){
        dis[++cnt]=w;
        for(int i=head[u];i;i=nxt[i]){
            if(to[i]==fa||dead[to[i]]) continue;
            getdis(to[i],u,w+val[i]);
        }
    }
    
    void calc(int u){
        disnum[0]=1;
        for(int i=head[u];i;i=nxt[i]){
            if(dead[to[i]]) continue;
            cnt=0;
            getdis(to[i],u,val[i]);
            for(int j=1;j<=cnt;j++){
                for(int k=0;k<3;k++)
                    (ans[(dis[j]%3+k)%3]+=dissum[k]+disnum[k]*dis[j]%mod)%=mod;
            }
            for(int j=1;j<=cnt;j++){
                (dissum[dis[j]%3]+=dis[j])%=mod;
                disnum[dis[j]%3]++;
            }
        }
        memset(dissum,0,sizeof(dissum));
        memset(disnum,0,sizeof(disnum));
    }
    
    void divide(int u){
        dead[u]=1;
        calc(u);
        for(int i=head[u];i;i=nxt[i]){
            if(dead[to[i]]) continue;
            maxp[rt=0]=sum=siz[to[i]];
            getrt(to[i],0);
            getrt(rt,0);
            divide(rt);
        }
    }
    
    void solve(){
        tot=0;
        memset(head,0,sizeof(head));
        memset(dead,0,sizeof(dead));
        memset(ans,0,sizeof(ans));
        for(int i=1,u,v,w;i<n;i++){
            scanf("%d%d%d",&u,&v,&w);
            u++,v++;
            add(u,v,w);add(v,u,w);
        }
        maxp[rt=0]=sum=n;
        getrt(1,0);
        getrt(rt,0);
        divide(rt);
        for(int i=0;i<3;i++) ans[i]=ans[i]*2%mod;
        printf("%lld %lld %lld
    ",ans[0],ans[1],ans[2]);
    }
    
    int main(){
    #ifndef ONLINE_JUDGE
        freopen("data.in","r",stdin);
        freopen("data.out","w",stdout);
    #endif
        while(~scanf("%d",&n)) solve();
        return 0;
    }
    

    其实用这种思想,写树形dp也不难了

  • 相关阅读:
    codeforce 896A
    CQH分治与整体二分
    [CQOI2011]动态逆序对
    codeforce Hello 2018 913F sol
    A*算法[k短路([SDOI2010]魔法猪学院)]
    bzoj3524 [POI2014]Couriers
    整体二分
    bzoj5016 [SNOI2017]一个简单的询问
    CF176E Archaeology
    bzoj4551 [TJOI2016&HEOI2016]树
  • 原文地址:https://www.cnblogs.com/BakaCirno/p/12307461.html
Copyright © 2020-2023  润新知