第3章-12 求整數的位數及各位數字之和 (15 分)
阿新 • • 發佈:2021-07-10
基礎點分治。
點分治的模板基礎上改一下即可。
詢問樹上長度模數是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); }