并不对劲的loj2050:p3248:[HNOI2016]树

题目大意

有一棵\(n\)个点的树,根为1号点,称它为“模板树”。
有一棵初始和模板树相同的树,称它为“当前树”。
对“当前树”有\(m\)次操作,每次操作给出两个数\(x,y\)表示将模板树中\(x\)及其子树复制下来并粘贴到模板树,该子树的根与点\(y\)连边,假设操作前“当前树”有\(a\)个点,“模板树”中\(x\)的子树大小为\(b\),则粘贴上去的\(b\)个点的标号按这棵子树在“模板树”中的标号从小到大的顺序依次标为\(a+1,a+2,...,a+b\)
\(m\)次操作后,有\(q\)次询问,每次问“当前树”上两点间的距离。
\(n,m,q\leq 10^5;\)

题解

建另一棵树:对于每次操作,粘贴过去的子树的根向点\(y\)所在的树的“根”连边(如果点\(y\)是之前的某一次粘贴过去的点,那么它的“根”是粘贴过去时子树的根,而不是整棵树的根)。
询问两点距离时分类讨论它们是不是同一次粘贴过去的。如果是就直接在模板树上求,如果不是就让它们分别走到和它们同一次粘贴过去的子树的根,再在新树中求LCA。

代码
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<iomanip>
#include<iostream>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<vector>
#define rep(i,x,y) for(register int i=(x);i<=(y);++i)
#define dwn(i,x,y) for(register int i=(x);i>=(y);--i)
#define view(u,k) for(int k=fir[u];~k;k=nxt[k])
#define maxn 100007
#define maxnd 2000007
#define LL long long
#define pll pair<LL,LL>
#define fi first
#define se second
#define mp make_pair
#define ls ch[u][0]
#define rs ch[u][1]
#define mi ((l+r)>>1)
using namespace std;
LL read()
{
	LL x=0,f=1;char ch=getchar();
	while(!isdigit(ch)&&ch!='-')ch=getchar();
	if(ch=='-')f=-1,ch=getchar();
	while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
	return x*f;
}
void write(LL x)
{
	if(x==0){putchar('0'),putchar('\n');return;}
	int f=0;char ch[20];
	if(x<0)putchar('-'),x=-x;
	while(x)ch[++f]=x%10+'0',x/=10;
	while(f)putchar(ch[f--]);
	putchar('\n');
	return;
}
struct nd{LL fa,start;int bac;}ad[maxn];
LL nowsiz,qu[maxn],qv[maxn],dis[maxn][20];
vector<pll>qx[maxn];
int rt[maxn],ch[maxnd][2],num[maxnd],siz[maxn],cntnd,cntad,cnte,dep2[maxn];
int n,m,q,fir[maxn],nxt[maxn<<1],v[maxn<<1],st[20][maxn<<1],tim,dfn[maxn],lg[maxn<<1],dep[maxn],anc[maxn][20];
map<LL,int>to;
void ade(int u1,int v1){v[cnte]=v1,nxt[cnte]=fir[u1],fir[u1]=cnte++;}
void getdfn(int u)
{
	st[0][++tim]=u,dfn[u]=tim,siz[u]=1;
	view(u,k)if(!dep[v[k]]&&v[k]!=1){dep[v[k]]=dep[u]+1,getdfn(v[k]),siz[u]+=siz[v[k]],st[0][++tim]=u;}
}
inline int lca(int x,int y)
{
	x=dfn[x],y=dfn[y];if(x>y)swap(x,y);
	int len=y-x+1;return dep[st[lg[len]][x]]<dep[st[lg[len]][y-(1<<lg[len])+1]]?st[lg[len]][x]:st[lg[len]][y-(1<<lg[len])+1];
}
inline int Dis(int x,int y){return dep[x]+dep[y]-2*dep[lca(x,y)];}
int getid(LL x)
{
	int L=1,R=m+1,res=-1;
	while(L<=R)
	{
		int mid=(L+R)>>1;
		if(ad[mid].start<=x)res=max(res,mid),L=mid+1;
		else R=mid-1;
	}
	return res;
}
inline void pu(int u){num[u]=0;if(ls)num[u]+=num[ls];if(rs)num[u]+=num[rs];return;}
int build(int l,int r,int x)
{
	int u=++cntnd;
	if(x<=l&&r<=x){num[u]=1;return u;}
	if(x<=mi)ls=build(l,mi,x);
	else rs=build(mi+1,r,x);
	num[u]=1;return u;
}
int merge(int u,int ub,int l,int r)
{
	if(!u||!ub){return u|ub;}
	ls=merge(ls,ch[ub][0],l,mi);
	rs=merge(rs,ch[ub][1],mi+1,r);
	pu(u);return u;
}
int ask(int u,int l,int r,int x)
{
	if(l==r)return l;
	if(!ls||num[ls]<x){x-=ls?num[ls]:0;return ask(rs,mi+1,r,x);}
	return ask(ls,l,mi,x);
}
void getto(int u)
{
	rt[u]=build(1,n,u);
	view(u,k)if(dep[v[k]]>dep[u]){getto(v[k]),rt[u]=merge(rt[u],rt[v[k]],1,n);}
	int li=qx[u].size()-1;
	rep(i,0,li){to[qx[u][i].fi]=ask(rt[u],1,n,qx[u][i].se);}
}
int main()
{
	n=read(),m=read(),q=read();
	rep(i,1,n)fir[i]=-1;
	rep(i,2,n){int x=read(),y=read();ade(x,y),ade(y,x);}
	getdfn(1);lg[0]=-1;
	rep(i,1,tim)lg[i]=lg[i>>1]+1;
	rep(i,1,lg[tim])for(int j=1;j+(1<<i)-1<=tim;j++)
		st[i][j]=dep[st[i-1][j]]<dep[st[i-1][j+(1<<(i-1))]]?st[i-1][j]:st[i-1][j+(1<<(i-1))]; 
	ad[1].bac=1,ad[1].fa=0,ad[1].start=1,nowsiz=n;
	rep(i,2,m+1)
	{
		int a=read();LL b=read();
		ad[i].bac=a,ad[i].fa=b,ad[i].start=nowsiz+1,nowsiz+=siz[a];//cout<<siz[a]<<" "<<a<<endl;
	}cntad=m;
	rep(i,2,m+1){int id=getid(ad[i].fa);anc[i][0]=id;qx[ad[id].bac].push_back(mp(ad[i].fa,ad[i].fa-ad[id].start+1));}
	rep(i,1,q)
	{
		qu[i]=read(),qv[i]=read();int idu=getid(qu[i]),idv=getid(qv[i]);
		qx[ad[idu].bac].push_back(mp(qu[i],qu[i]-ad[idu].start+1)),
		qx[ad[idv].bac].push_back(mp(qv[i],qv[i]-ad[idv].start+1));
	}
	getto(1);
	rep(i,2,m+1)
	{
		dis[i][0]=Dis(ad[anc[i][0]].bac,to[ad[i].fa])+1,dep2[i]=dep2[anc[i][0]]+1;
		rep(j,1,19)
		{
			anc[i][j]=anc[anc[i][j-1]][j-1];
			dis[i][j]=dis[i][j-1]+dis[anc[i][j-1]][j-1];
		}
	}
	rep(i,1,q)
	{
		LL ans=0,x=qu[i],y=qv[i],idx=getid(x),idy=getid(y);
		if(idx==idy){ans=Dis(to[x],to[y]);}
		else
		{
			if(dep2[idx]<dep2[idy])swap(idx,idy),swap(x,y);
			dwn(i,19,0)if(anc[idx][i]&&dep2[anc[idx][i]]>dep2[idy])
			{
				if(x&&to[x]!=ad[idx].bac)ans+=Dis(to[x],ad[idx].bac);
				ans+=dis[idx][i],idx=anc[idx][i],x=0;
			}
			if(anc[idx][0]==idy)
			{
				if(x&&to[x]!=ad[idx].bac)ans+=Dis(to[x],ad[idx].bac);x=0;
				ans+=Dis(to[ad[idx].fa],to[y])+1;
			}
			else 
			{
				if(dep2[idx]>dep2[idy])
				{
					if(x&&to[x]!=ad[idx].bac)ans+=Dis(to[x],ad[idx].bac);
					ans+=dis[idx][0],idx=anc[idx][0],x=0;
				}
				dwn(i,19,0)if(anc[idx][i]&&anc[idy][i]&&anc[idx][i]!=anc[idy][i])
				{
					if(x&&to[x]!=ad[idx].bac)ans+=Dis(to[x],ad[idx].bac);
					if(y&&to[y]!=ad[idy].bac)ans+=Dis(to[y],ad[idy].bac);
					ans+=dis[idx][i]+dis[idy][i],idx=anc[idx][i],idy=anc[idy][i];x=0,y=0;
				}
				if(x&&to[x]!=ad[idx].bac)ans+=Dis(to[x],ad[idx].bac);
				if(y&&to[y]!=ad[idy].bac)ans+=Dis(to[y],ad[idy].bac);
				ans+=Dis(to[ad[idx].fa],to[ad[idy].fa])+2;
			}
		}
		write(ans);
	}
	return 0;
}
posted @ 2020-06-12 07:47  echo6342  阅读(199)  评论(0编辑  收藏  举报