1. 程式人生 > 其它 >第3章-12 求整數的位數及各位數字之和 (15 分)

第3章-12 求整數的位數及各位數字之和 (15 分)

基礎點分治。

點分治的模板基礎上改一下即可。

詢問樹上長度模數是3的路徑

//詢問有多少路徑的長度加起來是3的倍數
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+10;
int n;
vector<pair<int,int> > g[maxn];
int vis[maxn],rt,sz[maxn],Tsz,wt[maxn],arr[maxn],cnt;
long long ans;
void getRoot (int u,int pre) {
	sz[u]=1;
	wt[u]=0;
	for (pair<int,int> it:g[u]) {
		int v=it.first;
		if (!vis[v]&&v!=pre) {
			getRoot(v,u);
			sz[u]+=sz[v];
			wt[u]=max(wt[u],sz[v]);
		}
	}
	wt[u]=max(wt[u],Tsz-sz[u]);
	if (wt[rt]>wt[u]) rt=u;
}
void dfs1 (int u,int dep,int pre) {
	arr[++cnt]=dep;
	for (pair<int,int> it:g[u]) {
		int v=it.first;
		if (v!=pre&&!vis[v]) dfs1(v,dep+it.second,u);
	}
}
int cc[4];
long long calc (int u,int dep) {
	cnt=0;
	dfs1(u,dep,0);
	memset(cc,0,sizeof(cc));
	for (int i=1;i<=cnt;i++) cc[arr[i]%3]++;
	long long ans=1ll*cc[0]*cc[0]+1ll*cc[1]*cc[2]+1ll*cc[1]*cc[2];
	return ans;
}
void dfs (int u) {
	ans+=calc(u,0);
	vis[u]=1;
	for (pair<int,int> it:g[u]) {
		int v=it.first;
		if (!vis[v]) {
			ans-=calc(v,it.second);//容斥減掉非法路徑 
			rt=0;
			Tsz=sz[v];
			getRoot(v,0);
			dfs(rt);
		} 
	}
}
int main () {
	scanf("%d",&n);
	for (int i=1;i<n;i++) {
		int u,v,w;
		scanf("%d%d%d",&u,&v,&w);
		g[u].push_back(make_pair(v,w));
		g[v].push_back(make_pair(u,w)); 
	}
	wt[rt=0]=1e9;
	Tsz=n;
	getRoot(1,0);
	dfs(rt);
	long long fm=1ll*n*n;
	long long gg=__gcd(ans,fm);
	ans/=gg;
	fm/=gg;
	printf("%lld/%lld",ans,fm);
}