BZOJ4535 [Hnoi2016]树

考虑每次复制操作,我们只需要知道复制这个子树的根以及原树就能知道新树里这一部分的形态,所以我们把每次复制操作复制的子树和最开始的一颗树都缩点,给每个缩点记录在原树里的根,父亲在原树里的编号。每个缩点和父亲缩点的距离为父亲在原树里与缩点父亲的根在原树里的距离+1,也就是这个缩点树的根到上一个缩点树的根在新树里的距离,维护原树和缩点树两个树倍增结构,询问的时候根据LCA在缩点树里的位置分类讨论即可

为了把新的编号和原树上的编号对应我们需要在原树上主席树查子树K小,强套主席树,差评

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<bitset>
using namespace std;
#define MAXN 100010
#define MAXM 2000010
#define ll long long
#define INF 1000000000
#define MOD 1000000007
#define eps 1e-8
struct vec{
	int to;
	int fro;
};
struct mul{
	int fa[MAXN][20];
	int dep[MAXN];
	ll dis[MAXN];
	void ins(int x,int y,int z);
	int acs(int x,int y);
	int lca(int x,int y);
	ll D(int x,int y);
};
int n,m,q;
mul t1,t2;
int dfn[MAXN],tim;
int rt[MAXN];
int son[MAXM][2],Siz[MAXM],tot;
int siz[MAXN];
vec mp[MAXN*2];
int tai[MAXN],cnt;
ll st[MAXN];
int sz[MAXN],r[MAXN],c[MAXN],N;
inline void be(int x,int y){
	mp[++cnt].to=y;
	mp[cnt].fro=tai[x];
	tai[x]=cnt;
}
inline void bde(int x,int y){
	be(x,y);
	be(y,x);
}
void change(int &x,int xx,int l,int r,int p){
	x=++tot;
	memcpy(son[x],son[xx],sizeof(son[x]));
	Siz[x]=Siz[xx]+1;
	if(l==r){
		return ;
	}
	int mid=l+r>>1;
	if(p<=mid){
		change(son[x][0],son[xx][0],l,mid,p);
	}else{
		change(son[x][1],son[xx][1],mid+1,r,p);
	}
}
void mul::ins(int x,int y,int z){
	int j,t;
	dis[y]=dis[x]+z;
	dep[y]=dep[x]+1;
	for(j=1,t=x;t;j++){
		fa[y][j]=t;
		t=fa[t][j];
	}
}
int mul::lca(int x,int y){
	int i;
	if(dep[x]<dep[y]){
		swap(x,y);
	}
	for(i=19;i;i--){
		if(dep[fa[x][i]]>=dep[y]){
			x=fa[x][i];
		}
	}
	for(i=19;i;i--){
		if(fa[x][i]!=fa[y][i]){
			x=fa[x][i];
			y=fa[y][i];
		}
	}
	return x==y?x:fa[x][1];
}
ll mul::D(int x,int y){
	int z=lca(x,y);
	return dis[x]+dis[y]-2*dis[z];
}
int mul::acs(int x,int y){
	int k=1;
	while(y){
		if(y&1){
			x=fa[x][k];
		}
		k++;
		y>>=1;
	}
	return x;
}
void dfs(int x){
	int i,j,y,t;
	dfn[x]=++tim;
	siz[x]=1;
	change(rt[tim],rt[tim-1],1,n,x);
	for(i=tai[x];i;i=mp[i].fro){
		y=mp[i].to;
		if(!dfn[y]){
			t1.ins(x,y,1);
			dfs(y);
			siz[x]+=siz[y];
		}
	}
}
int bel(ll x){
	int re;
	int l=1,r=N;
	while(l<=r){
		int mid=l+r>>1;
		if(st[mid]<=x){
			re=mid;
			l=mid+1;
		}else{
			r=mid-1;
		}
	}
	return re;
}
int kth(int x,int xx,int l,int r,int k){
	if(l==r){
		return l;
	}
	int t=Siz[son[xx][0]]-Siz[son[x][0]];
	int mid=l+r>>1;
	if(k<=t){
		return kth(son[x][0],son[xx][0],l,mid,k);
	}else{
		return kth(son[x][1],son[xx][1],mid+1,r,k-t);
	}
}
int find(ll x,int y){
	return kth(rt[dfn[r[y]]-1],rt[dfn[r[y]]+siz[r[y]]-1],1,n,x-st[y]+1);
}
int main(){
	/*
	freopen("tree13.in","r",stdin);
	freopen("aw.out","w",stdout);
	//*/
	int i,xx,yy,z,zz,bx,by;
	ll x,y;
	scanf("%d%d%d",&n,&m,&q);
	for(i=1;i<n;i++){
		scanf("%lld%lld",&x,&y);
		bde(x,y);
	}
	t1.dep[1]=t2.dep[1]=1;
	dfs(1);
	st[++N]=1;
	sz[N]=n;
	r[N]=1;
	c[N]=0;
	for(i=1;i<=m;i++){
		scanf("%lld%lld",&x,&y);
		z=bel(y);
		yy=find(y,z);
		t2.ins(z,++N,t1.dis[yy]-t1.dis[r[z]]+1);
		st[N]=st[N-1]+sz[N-1];
		r[N]=x;
		sz[N]=siz[x];
		c[N]=yy;
	}
	for(i=1;i<=q;i++){
		scanf("%lld%lld",&x,&y);
		bx=bel(x);
		by=bel(y);
		xx=find(x,bx);
		yy=find(y,by);
		ll re=0;
		re+=t2.D(bx,by);
		int L=t2.lca(bx,by);
		if(bx==L&&by==L){
			re+=t1.D(xx,yy);
		}else if(bx!=L&&by!=L){
			re+=t1.dis[xx]-t1.dis[r[bx]];
			xx=c[t2.acs(bx,t2.dep[bx]-t2.dep[L]-1)];
			re+=t1.dis[yy]-t1.dis[r[by]];
			yy=c[t2.acs(by,t2.dep[by]-t2.dep[L]-1)];
			re-=(t1.dis[t1.lca(xx,yy)]-t1.dis[r[L]])*2;
		}else if(L!=bx){
			re+=t1.dis[xx]-t1.dis[r[bx]];
			xx=c[t2.acs(bx,t2.dep[bx]-t2.dep[L]-1)];
			z=t1.lca(xx,yy);
			zz=r[L];
			re-=t1.dis[z]-t1.dis[zz];
			re+=t1.dis[yy]-t1.dis[z];
		}else{
			re+=t1.dis[yy]-t1.dis[r[by]];
			yy=c[t2.acs(by,t2.dep[by]-t2.dep[L]-1)];
			z=t1.lca(xx,yy);
			zz=r[L];
			re-=t1.dis[z]-t1.dis[zz];
			re+=t1.dis[xx]-t1.dis[z];
		}
		printf("%lld\n",re);
	}
	return 0;
}

/*
5 3 2
2 1
3 2
4 2
5 3

4 2
3 4
5 5

8 6
1 4

*/
</span>


你可能感兴趣的:(BZOJ4535 [Hnoi2016]树)