点分治
今天学的算法,呀。其实之前打比赛时做到过类似的题目。
当时没有去补题,感觉怪难的。现在学学。
点分治主要是用于求解树上路径类的问题。
这题如果能想到点分治的话,思路其实还是挺清晰的。
但是,刚学,我板子写错了哦
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=1e5+100;
const int inf=1e9;
struct edge{
int to,cost,next;
}E[N<<1];
int head[N];
int cnt=1;
void add(int from,int to,int cost){
E[cnt].to=to;E[cnt].cost=cost;
E[cnt].next=head[from];
head[from]=cnt++;
}
int root;
int maxson[N],size[N];
int sig;
bool vis[N];
void getroot(int u,int fa){
size[u]=1;maxson[u]=0;
for (int i=head[u];i;i=E[i].next){
int v=E[i].to;int cost=E[i].cost;
if (vis[v]||v==fa)continue;
getroot(v,u);
size[u]+=size[v];
maxson[u]=max(maxson[u],size[v]);
}maxson[u]=max(maxson[u],sig-size[u]);
if(maxson[u]<maxson[root])root=u;
}
ll res[3];
void getrood(int u,int fa,ll len){
res[len%3]++;
for (int i=head[u];i;i=E[i].next){
int v=E[i].to;int cost=E[i].cost;
if (vis[v]||v==fa)continue;
getrood(v,u,len+cost);
}
}
ll Solve(int u,ll len){
res[0]=res[1]=res[2]=0;
getrood(u,0,len);
return res[0]*res[0]+res[1]*res[2]*2;
}
ll ans=0;
void dfs(int u){
vis[u]=1;
ans+=Solve(u,0);
for (int i=head[u];i;i=E[i].next){
int v=E[i].to;int cost=E[i].cost;
if (vis[v])continue;
ans-=Solve(v,cost);
root=0;sig=size[v];
getroot(v,u);
dfs(root);
}
}
int n;
int main(){
ios::sync_with_stdio(0);
cin>>n;
for (int i=1,u,v,w;i<n;++i){
cin>>u>>v>>w;w%=3;
add(u,v,w);add(v,u,w);
}
sig=n;root=0;
maxson[0]=inf;
getroot(1,0);
dfs(root);
ll c=__gcd(ans,(ll)n*(ll)n);
cout<<ans/c<<"/"<<(ll)n*(ll)n/c<<endl;
}
京公网安备 11010502036488号