zoukankan      html  css  js  c++  java
  • 洛谷 P2634 [国家集训队]聪聪可可(点分治)

    传送门
    在做一道点分治练练手。
    主要就是求树上长度为 (3) 的倍数的路径的数量,当然还是用点分治更方便
    记录路径长度 (\%3) 后的数的数量,然后通过当前路径找能和它凑成 (3) 的倍数的路径有多少条
    由于是一个偏序,所以答案要 ( imes 2),当然还要加 (i->i) 的方案总共 (n) 条。

    #include <bits/stdc++.h>
    using namespace std;
    const int MAXN=2e4+10;
    int n;
    int head[MAXN],to[MAXN*2],nxt[MAXN*2],val[MAXN*2],tot;
    int siz[MAXN],maxp[MAXN],sum,rt,dead[MAXN];
    int path[4],cnt,dis[MAXN],ans;
    
    void add(int u,int v,int w){
        to[++tot]=v;nxt[tot]=head[u];val[tot]=w;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){
        path[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++)
                if(dis[j]%3==0) ans+=path[0];
                else ans+=path[3-dis[j]%3];
            for(int j=1;j<=cnt;j++) path[dis[j]%3]++;
        }
        memset(path,0,sizeof(path));
    }
    
    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);
        }
    }
    
    int gcd(int a,int b){return b==0?a:gcd(b,a%b);}
    
    int main(){
    #ifndef ONLINE_JUDGE
        freopen("data.in","r",stdin);
        freopen("data.out","w",stdout);
    #endif
        scanf("%d",&n);
        for(int i=1,u,v,w;i<n;i++){
            scanf("%d%d%d",&u,&v,&w);
            add(u,v,w);add(v,u,w);
        }
        maxp[0]=sum=n;
        getrt(1,0);
        getrt(rt,0);
        divide(rt);
        ans=ans*2+n;
        int a=ans,b=n*n,d=gcd(a,b);
        printf("%d/%d
    ",a/d,b/d);
        return 0;
    }
    
  • 相关阅读:
    any、some、all for sql
    Date CONVERT() 函数
    Config Database
    移动master 数据库
    使用 OpenRowSet 和 OpenDataSource 访问 Excel 972007
    动态管理视图和函数
    SQL Server 2005 Merge Replication Step by Step Procedure
    系统试图(返回表所有记录数及所有的 identity 列)
    js if without curly brackets bug All In One
    Web3 All In One
  • 原文地址:https://www.cnblogs.com/BakaCirno/p/12302574.html
Copyright © 2011-2022 走看看