P2634 [国家集训队]聪聪可可

基础点分治。

点分治的模板基础上改一下即可。

询问树上长度模数是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);
}
posted @ 2021-07-20 13:57  zlc0405  阅读(33)  评论(0编辑  收藏  举报