【BZOJ4539】【HNOI2016】—树(主席树)

传送门

真·树套树

因为每次复制的都是原树的子树

所以我们考虑直接在新树上加一个点来记录这是原树中的哪个点的子树
边权设为儿子在父亲子树中连接的点到父亲的根的距离

至于编号是一段连续的区间,可以直接记录每一段二分查找
具体的点相当于原树子树中查找第kk大,一个主席树记录一下
查询距离的时候先计算出u,v,lcau,v,lca三个根之间的距离

然后分类讨论一下u,vu,vlcalca子树中连接的点之间的距离和真正点与根的距离

复杂度O(nlogn)O(nlogn)
实现可以看代码

注意开long longlong\ long

#include<bits/stdc++.h>
using namespace std;
#define ll long long
inline int read(){
	char ch=getchar();
	int res=0,f=1;
	while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
	while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=getchar();
	return res*f;
}
inline ll readl(){
	char ch=getchar();
	ll res=0,f=1;
	while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
	while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=getchar();
	return res*f;
}
const int N=100005,Log=22;
int in[N],out[N],dfn,n,m,q,idx,fa[N],rt[N];
ll cnt[N];
#define mid ((l+r)>>1)
struct Pres_Tree{
	int rt[N],siz[N*Log],lc[N*Log],rc[N*Log],tot;
	void insert(int &u,int r1,int l,int r,int k){
		u=++tot,siz[u]=siz[r1]+1,lc[u]=lc[r1],rc[u]=rc[r1];
		if(l==r)return;
		if(k<=mid)insert(lc[u],lc[r1],l,mid,k);
		else insert(rc[u],rc[r1],mid+1,r,k);
	}
	inline void ins(int p,int k){insert(rt[p],rt[p-1],1,n,k);}
	int query(int r1,int r2,int l,int r,int k){
		if(l==r)return l;
		int del=siz[lc[r2]]-siz[lc[r1]];
		if(del>=k)return query(lc[r1],lc[r2],l,mid,k);
		else return query(rc[r1],rc[r2],mid+1,r,k-del);
	}
	inline int qry(int l,int r,int k){return query(rt[l-1],rt[r],1,n,k);}
}T;
struct G{
	int adj[N<<1],nxt[N<<1],to[N<<1],val[N<<1],dep[N],siz[N],f[N][Log],cnt;
	ll dis[N];
	inline void addedge(int u,int v,int w){
		nxt[++cnt]=adj[u],adj[u]=cnt,to[cnt]=v,val[cnt]=w;
	}
	inline void add(int u,int v,int w){
		addedge(u,v,w),addedge(v,u,w);
	}
	void dfs1(int u){
		for(int i=1;i<=20;i++)f[u][i]=f[f[u][i-1]][i-1];
		for(int e=adj[u];e;e=nxt[e]){
			int v=to[e];
			if(v==f[u][0])continue;
			f[v][0]=u,dep[v]=dep[u]+1;
			dis[v]=dis[u]+val[e],dfs1(v);
		}
	}
	void dfs2(int u){
		siz[u]=1,in[u]=++dfn,T.ins(dfn,u);
		for(int e=adj[u];e;e=nxt[e]){
			int v=to[e];
			if(v==f[u][0])continue;
			dfs2(v),siz[u]+=siz[v];	
		}
		out[u]=dfn;
	}
	inline int up(int u,int k){
		for(int i=20;~i;i--){
			if(k&(1<<i))u=f[u][i];
		}
		return u;
	}
	inline int Lca(int u,int v){
		if(dep[u]<dep[v])swap(u,v);
		u=up(u,dep[u]-dep[v]);
		if(u==v)return u;
		for(int i=20;~i;i--)
		if(f[u][i]!=f[v][i])u=f[u][i],v=f[v][i];
		return f[u][0];
	}
	inline ll dist(int u,int v){
		return dis[u]+dis[v]-2ll*dis[Lca(u,v)];
	}
	inline int firson(int u,int v){
		return up(u,dep[u]-dep[v]-1);
	} 
}A,B;
inline int getid(ll u){
	return lower_bound(cnt+1,cnt+idx+1,u)-cnt;
}
inline ll query(ll u,ll v){
	int id1=getid(u),r1=rt[id1];u=T.qry(in[r1],out[r1],u-cnt[id1-1]);
	int id2=getid(v),r2=rt[id2];v=T.qry(in[r2],out[r2],v-cnt[id2-1]);
	int lca=B.Lca(id1,id2);
	if(id1==id2)return A.dist(u,v);
	ll res=B.dist(id1,id2)+A.dis[u]-A.dis[r1]+A.dis[v]-A.dis[r2];
	if(id1==lca){
		int fir=fa[B.firson(id2,id1)];
		res-=(A.dis[u]-A.dis[r1])+(A.dis[fir]-A.dis[r1])-A.dist(u,fir);
	}
	else if(id2==lca){
		int fir=fa[B.firson(id1,id2)];
		res-=(A.dis[v]-A.dis[r2])+(A.dis[fir]-A.dis[r2])-A.dist(v,fir);
	}
	else{
		int fira=fa[B.firson(id1,lca)],firb=fa[B.firson(id2,lca)];
		res-=(A.dis[fira]-A.dis[rt[lca]]+A.dis[firb]-A.dis[rt[lca]]-A.dist(fira,firb));
	}
	return res;
}
signed main(){
	n=read(),m=read(),q=read();
	for(int i=1;i<n;i++){
		int u=read(),v=read();
		A.add(u,v,1);
	}
	A.dfs1(1),A.dfs2(1);
	cnt[1]=n,idx=1,rt[1]=1;ll newn=n;
	for(int i=2;i<=m+1;i++){
		ll u=readl(),v=readl();
		int id=getid(v),root=rt[id];
		rt[i]=u,idx=i,fa[i]=T.qry(in[root],out[root],v-cnt[id-1]);
		B.add(i,id,A.dis[fa[i]]-A.dis[root]+1);
		newn+=A.siz[u],cnt[i]=newn;
	}B.dfs1(1);
	for(int i=1;i<=q;i++){
		ll u=readl(),v=readl();
		cout<<query(u,v)<<'\n';
	}
}
posted @ 2019-03-27 07:42  Stargazer_cykoi  阅读(99)  评论(0编辑  收藏  举报