zoukankan      html  css  js  c++  java
  • 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也不难了

  • 相关阅读:
    Roce ofed 环境搭建与测试
    Ubuntu 1804 搭建NFS服务器
    Redhat 8.0.0 安装与网络配置
    Centos 8.1 安装与网络配置
    SUSE 15.1 系统安装
    VSpare ESXi 7.0 基本使用(模板、iso、SRIOV)
    VSpare ESXi 7.0 服务器安装
    open SUSE leap 15.1 安装图解
    KVM虚拟机网卡连接网桥
    GitHub Action一键部署配置,值得拥有
  • 原文地址:https://www.cnblogs.com/BakaCirno/p/12307461.html
Copyright © 2011-2022 走看看