1. 程式人生 > >聰聰可可(BZOJ 2152)

聰聰可可(BZOJ 2152)

傳送門

題意

給定一棵邊帶權樹,問有多少個點對,其簡單路徑上的權值和為3的倍數

分析

這和之前做過的Tree POJ 1741有異曲同工之妙,解決樹上的點對(路徑)關係,我們自然想到了分治演算法 問題就變得簡單起來,我們只需要思考如何統計路徑和為3的倍數的點對,其他的就按照點分治的一般套路走 上一道例題,我們是記錄的dis[i],表示 i 這個點到重心的距離,然後按距離排序,二分,求得方案數 搬到這道題上,顯然行不通了,如果還是按同樣的定義,我們就只能n2統計(n ☞ 點的個數) 怎麼辦呢?我也不知道啊 但題解知道:統計一下每個點到重心的距離模 3 後的值出現的次數,即 sum[i] 就表示到重心路徑模 3 為 i 的點的總數(當然 i 只可能為 0,1 或者 2 ) 那麼總共的 ans=sum0∗sum0+2∗sum1∗sum2 ​還要乘 2 的原因是順序不同的點對是不同的(比如 (2,3),(3,2) 是不同的) 當然由於重複計算,在遞迴到子樹時,還要將部分答案減掉 而總情況顯然是 n2

程式碼

#include<bits/stdc++.h>
#define in  read()
#define N 20009
using namespace std;
inline int read(){
	char ch;int f=1,res=0;
	while((ch=getchar())<'0'||ch>'9') if(ch=='-') f=-1;
	while(ch>='0'&&ch<='9'){
		res=(res<<3)+(res<<1)+ch-'0';
		ch=getchar();
	}
	return f==1
?res:-res; } int n,maxn,ans=0,sum[5],G; int nxt[N<<1],to[N<<1],head[N],w[N<<1],cnt=0; int sze[N],son[N]; bool vis[N]; void add(int x,int y,int z){ nxt[++cnt]=head[x];head[x]=cnt;to[cnt]=y;w[cnt]=z; nxt[++cnt]=head[y];head[y]=cnt;to[cnt]=x;w[cnt]=z; } int gcd(int x,int y){ int z=x%
y; while(z){x=y;y=z;z=x%y;} return y; } void getsize(int u,int fu){ sze[u]=1;son[u]=0; for(int e=head[u];e;e=nxt[e]){ int v=to[e]; if(!vis[v]&&v!=fu){ getsize(v,u); sze[u]+=sze[v]; if(sze[v]>son[u]) son[u]=sze[v]; } } } void getG(int rt,int u,int fu){//based on now son[u]=max(son[u],sze[rt]-sze[u]); if(son[u]<maxn){ maxn=son[u]; G=u; } for(int e=head[u];e;e=nxt[e]){ int v=to[e]; if(!vis[v]&&v!=fu) getG(rt,v,u); } } void getdis(int u,int fu,int d){ sum[d%3]++; for(int e=head[u];e;e=nxt[e]){ int v=to[e]; if(!vis[v]&&v!=fu){ getdis(v,u,d+w[e]); } } } int calc(int u,int L){ memset(sum,0,sizeof(sum)); getdis(u,0,L); return sum[0]*sum[0]+sum[1]*sum[2]*2; } void solve(int u){ maxn=n; getsize(u,0); getG(u,u,0); vis[G]=1; ans+=calc(G,0); for(int e=head[G];e;e=nxt[e]){ int v=to[e]; if(!vis[v]){ ans-=calc(v,w[e]); solve(v); } } } int main(){ n=in; int i,j,k; for(i=1;i<n;++i){ int x=in,y=in,w=in; add(x,y,w); } solve(1); n*=n; int gd=gcd(ans,n); ans/=gd;n/=gd; printf("%d/%d",ans,n); return 0; }