题意:求一棵树上有多少个三元组{x,y,z}满足x<y<z且两两距离相同。
解法1:
启发式合并,每个点继承最大的孩子的信息,用指针O(1)转移,其余孩子O(size)加入,这样可以维护子树中所有节点的深度信息和所有二元组{x,y},x,y深度相同且在同一棵子树中的个数。然后就可以算了,复杂度是O(nlogn)
#include<bits/stdc++.h>
#define N 1000100
using namespace std;
struct Node{
vector<long long> lg;
vector<long long> dis;
int f;
int size(){
return dis.size();
}
void clear(){
dis.clear();lg.clear();
f=0;
}
}*fr[N],re[N];
inline int cmp(int a,int b){
return fr[a]->size()>fr[b]->size();
}
int n,len;
long long ans=0;
int to[N<<1],beg[N],nex[N<<1];
vector<int> s;
inline void Add(int a,int b){
nex[++len]=beg[a],beg[a]=len,to[len]=b;
nex[++len]=beg[b],beg[b]=len,to[len]=a;
}
void dfs(int p,int fa){
for(int i=beg[p];i;i=nex[i])
if(to[i]!=fa) dfs(to[i],p);
s.clear();
for(int i=beg[p];i;i=nex[i])
if(to[i]!=fa) s.push_back(to[i]);
if(!s.size()){
fr[p]=re+p;
fr[p]->dis.push_back(1);
fr[p]->lg.push_back(0);
return;
}
sort(s.begin(),s.end(),cmp);
fr[p]=fr[s[0]];
fr[p]->f++;
int fp=fr[p]->f;
fr[p]->lg.push_back(0);fr[p]->lg.push_back(0);
fr[p]->dis.push_back(1);
ans+=fr[p]->lg[fp];
for(int i=1;i<s.size();i++){
int v=s[i],fv=fr[v]->f;
for(int i=0;i<=fv;i++)
ans+=(fr[v]->dis[fv-i])*(fr[p]->lg[i+fp+1]);
for(int i=1;i<=fv;i++)
ans+=(fr[v]->lg[fv+i])*(fr[p]->dis[fp-i+1]);
for(int i=0;i<=fv;i++)
fr[p]->lg[i+fp+1]+=(fr[v]->dis[fv-i])*(fr[p]->dis[fp-i-1]);
for(int i=1;i<=fv;i++)
fr[p]->lg[i+fp-1]+=fr[v]->lg[i+fv];
for(int i=0;i<=fv;i++)
fr[p]->dis[fp-(i+1)]+=fr[v]->dis[fv-i];
}
}
int main(){
scanf("%d",&n);
for(int i=1,a,b;i<n;i++){
scanf("%d%d",&a,&b);
Add(a,b);
}
for(int i=0;i<=n;i++) re[i].clear();
dfs(1,0);
printf("%lld\n",ans);
return 0;
}
解法2:
长链剖分,待补全