把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

luogu P5904 [POI2014]HOT-Hotels 加强版

题面传送门
这个东西肯定是有一个中转点满足到三个点距离相同。
我们设\(f_{i,j}\)\(i\)子树内的距离\(i\)\(j\)的点的个数,\(g_{i,j}\)\(i\)子树内无序对\((x,y)\)满足\(dist(x,lca(x,y))=dist(y,lca(x,y))=dist(i,lca(x,y))+j\)
这个东西的转移是\(g_{u,i}=g_{v}{i}+f_{u,i}*f_{v,i-1}\)\(f\)随便转移。
然后因为和深度有关所以直接上从长链剖分就好了。时间复杂度\(O(n)\)
code:

#include<bits/stdc++.h>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define re register
#define ll long long
#define db double
#define N 500000
#define K 150
#define mod 10007
#define eps (1e-9)
#define U unsigned int
#define it iterator
#define Gc() getchar() 
#define Me(x,y) memset(x,y,sizeof(x))
#define d(x,y) (n*(x-1)+(y))
using namespace std;
int n,x,y,d[N+5],len[N+5],son[N+5];ll Ans,f[N+5],g[N+5],*F[N+5],*G[N+5],*Fh=f,*Gh=g;
struct yyy{int to,z;}tmp;
struct ljb{int head,h[N+5];yyy f[N+5<<1];I void add(int x,int y){f[++head]=(yyy){y,h[x]};h[x]=head;}}s;I void Make(int x){F[x]=Fh;Fh+=len[x]+2;Gh+=len[x]+2;G[x]=Gh;Gh+=len[x]+2;}
I void dfs1(int x,int last){yyy tmp;for(int i=s.h[x];i;i=tmp.z) tmp=s.f[i],tmp.to^last&&(dfs1(tmp.to,x),len[son[x]]<len[tmp.to]&&(son[x]=tmp.to));len[x]=len[son[x]]+1;}
I void dfs2(int x,int last){
	re int i,j;yyy tmp;F[x][0]=1;if(!son[x]) return;F[son[x]]=F[x]+1;G[son[x]]=G[x]-1;dfs2(son[x],x);Ans+=G[x][0];for(int i=s.h[x];i;i=tmp.z){
		tmp=s.f[i];if(tmp.to==son[x]||tmp.to==last) continue;Make(tmp.to);dfs2(tmp.to,x);for(j=1;j<=len[tmp.to];j++) Ans+=F[x][j-1]*G[tmp.to][j];for(j=0;j<=len[tmp.to];j++) Ans+=F[tmp.to][j]*G[x][j+1];
		for(j=1;j<=len[tmp.to]+1;j++) G[x][j]+=G[tmp.to][j+1]+F[x][j]*F[tmp.to][j-1];for(j=1;j<=len[tmp.to];j++) F[x][j]+=F[tmp.to][j-1];
	}
}
int main(){
	freopen("1.in","r",stdin);
	re int i,j,h;scanf("%d",&n);for(i=1;i<n;i++)scanf("%d%d",&x,&y),s.add(x,y),s.add(y,x);dfs1(1,0);Make(1);dfs2(1,0);printf("%lld\n",Ans);
}
posted @ 2021-08-08 14:30  275307894a  阅读(33)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end