zoukankan      html  css  js  c++  java
  • BZOJ 2152 (点分治)

    题目:https://vjudge.net/contest/307753#problem/G

    题意: 一棵树让你求总的路径条数和 %3的路径条数

    思路:点分治水题

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<iostream> 
    #include<vector>
    #include<queue>
    #define maxn 100005
    #define mod 0x3f3f3f3f
    using namespace std;
    typedef long long ll;
    ll da;
    vector<pair<ll,ll> > mp[maxn],xx[maxn];//存下图 
    ll e[maxn];
    bool vis[maxn];//标记曾经使用过的重心 
    ll maxsize[maxn],dis[maxn],d[maxn],flag[maxn];//maxsize 当前节点的最大子树 
    ll siz[maxn],xd[maxn];// dis 到重心的距离  d 出现过的距离 
    ll n,m,k,rt,sum,qe,qe2,ans1,ans2;  // siz 当前节点的子树个数  e 出现的距离  rt代表当前重心 
    void find(ll x,ll f){//找出重心 
        siz[x]=1;
        maxsize[x]=0;
        for(int i=0;i<mp[x].size();i++){
            pair<ll,ll> q=mp[x][i];
            if(q.first==f||vis[q.first]) continue;//vis数组标记曾经使用过的重心 
            find(q.first,x);
            siz[x]+=siz[q.first];
            maxsize[x]=max(maxsize[x],siz[q.first]); 
        } 
        maxsize[x]=max(maxsize[x],sum-siz[x]);//节点总数减去当前的子树数=以当前节点为根的父亲点子树数 
        if(maxsize[x]<maxsize[rt]){
            rt=x;
        } 
    }
    void query(ll z,ll sm){
        if(z>ans1){
            ans1=z;
            ans2=sm;
        }
        else if(z==ans1){
            ans2+=sm;
        }
    }
    void get_dis(ll x,ll f,ll len){
        
        if(len%3==0) ans1++;
        ans2++;
        ans1+=flag[(3-len%3+3)%3];
        ans2+=flag[0]+flag[1]+flag[2];
        e[len%3]++;
        for(int i=0;i<mp[x].size();i++){
            pair<ll,ll> q=mp[x][i];
            if(q.first==f||vis[q.first]) continue;
            //dis[q.first]=(dis[x]+len)%3;
            get_dis(q.first,x,(len+q.second)%3);
        }    
    }
    void divide(ll x){
        vis[x]=1;
        //printf("rt=%lld ans1=%lld ans2=%lld
    ",x,ans1,ans2);
        for(int i=0;i<mp[x].size();i++){
            pair<ll,ll> q=mp[x][i];
            if(vis[q.first]) continue;
            //dis[x]=q.second;
            get_dis(q.first,x,q.second%3);
            for(int j=0;j<3;j++){
                flag[j]+=e[j];
                e[j]=0;
            }
        }
        for(int i=0;i<3;i++){
            flag[i]=0;
        }
        for(int i=0;i<mp[x].size();i++){
            pair<ll,ll> q=mp[x][i];
            if(vis[q.first]) continue;
            //if(da>0) break;
            sum=siz[q.first];
            rt=0;
            maxsize[rt]=mod;
            find(q.first,x);
            divide(rt);
        }
    //    vis[x]=0;
    }
    void init(){
        ans1=0;ans2=0;
        for(int i=0;i<=n;i++) mp[i].clear();
        for(int i=0;i<=n;i++) vis[i]=0;
        for(int i=0;i<3;i++) flag[i]=0;
    } 
    int main(){
        ll t;
        while(scanf("%lld",&n)!=EOF){
            ll a,b,c;
            init();
            for(int i=1;i<=n-1;i++){
                scanf("%lld%lld%lld",&a,&b,&c);
                mp[a].push_back(make_pair(b,c));
                mp[b].push_back(make_pair(a,c)); 
            }    
            sum=n;//当前节点数 
            rt=0;
            maxsize[0]=mod;//置初值 
            find(1,0);
            divide(rt);
            ans1*=2;
            ans2*=2;
            ans1+=n;
            ans2+=n;
            ll w=__gcd(ans1,ans2);
            //printf("%lld/%lld
    ",ans1,ans2);
            printf("%lld/%lld
    ",ans1/w,ans2/w);
        
        }
    } 
  • 相关阅读:
    网络编程基础
    面试题
    面试题合集
    异常
    三个重要的模块loggning,hashlib,configparse
    面向对象进阶
    单例模式
    反射
    封装
    开发规范
  • 原文地址:https://www.cnblogs.com/Lis-/p/11365917.html
Copyright © 2011-2022 走看看