题目: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); } }