[HNOI2016] 树 题解

[HNOI2016] 树 题解


题意简述

给定一棵 \(n\) 个点的模版树,然后 \(m\) 次地将它的某棵子树复制到另一棵大树上,然后 \(Q\) 次查询结点间距。

分析

比较简单,只是实现较烦琐。

\(30\%\)

\(n,m \le 500\),尝试把模版树的每棵子树都预处理出来,复制时暴力建树,然后倍增求 LCA 即可。复杂度 \(O((Q+nm)\log_2{nm})\)

\(60\%\)

\(n\le 3000\),依旧是把模版树的每棵子树都预处理出来,但是要把每个复制的子树当成一个大节点,然后求 LCA 时先在大节点上倍增,再转回原树节点上,再转回来,复杂度 \(O(n^2+(Q+m)(\log_2{n}+\log_2{m}))\) 之类的。

//#define Plus_Cat ""
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define LINF 0x3f3f3f3f
#define ll int
#define RCL(a,b,c,d) memset(a,b,sizeof(c)*(d))
#define tomin(a,...) ((a)=min({(a),__VA_ARGS__}))
#define tomax(a,...) ((a)=max({(a),__VA_ARGS__}))
#define FOR(i,a,b) for(int i(a); i<=(int)(b); ++i)
#define DOR(i,a,b) for(int i(a); i>=(int)(b); --i)
#define EDGE(g,i,x,y) for(int i(g.h[x]),y(g[i].v); ~i; y=g[i=g[i].nxt].v)
using namespace std;
constexpr int N(1e5+10),M(250500+10);

namespace IOEcat {
#define isD(c) ('0'<=(c)&&(c)<='9')
#define DE(...) E(#__VA_ARGS__,__VA_ARGS__)
	struct Icat {

		char getc() {
			return getchar();
		}

		template<class T>void operator ()(T &x) {
			static bool sign(0);
			static char ch(0);
			sign=0,x=0;
			while(ch=getc(),!isD(ch))if(ch=='-')sign=1;
			do x=(x<<1)+(x<<3)+(ch^48);
			while(ch=getc(),isD(ch));
			if(sign)x=-x;
		}

		template<class T,class...Types>void operator ()(T &x,Types&...args) {
			return (*this)(x),(*this)(args...);
		}

	} I;
	struct Ocat {

		void putc(char c) {
			putchar(c);
		}

		template<class T>void operator ()(T x,const char lst='\n') {
			static int top(0);
			static char st[100];
			if(x<0)x=-x,putc('-');
			do st[++top]=(x%10)^48,x/=10;
			while(x);
			while(top)putc(st[top--]);
			putc(lst);
		}

		template<class T,class...Types>void operator ()(const T x,const char lst='\n',const Types...args) {
			return (*this)(x,lst),(*this)(args...);
		}

	} O;
	struct Ecat {

		template<class T>void operator ()(const char *fmt,const T x) {
			cerr<<fmt<<':'<<x<<'.'<<endl;
		}

		template<class T,class...Types>void operator ()(const char *fmt,const T x,const Types...args) {
			while(*fmt^',')cerr<<*fmt++;
			return cerr<<':'<<x<<" ,",(*this)(++fmt,args...);
		}

	} E;

} using namespace IOEcat;

int n,m,Q,idx;
int dl[N],dr[N],fa[M],dep[M],dfn[N],siz[N],son[N],top[N];
struct CFS {
	int tot,h[M];
	struct edge {
		int v,nxt;
		
		edge(int v=0,int nxt=-1):v(v),nxt(nxt) {}
		
	} e[M<<1];
	
	edge &operator [](int i) {
		return e[i];
	}
	
	void Init() {
		tot=-1,RCL(h,-1,h,1);
	}
	
	void att(int u,int v) {
		e[++tot]=edge(v,h[u]),h[u]=tot;
	}
	
	void con(int u,int v) {
		att(u,v),att(v,u);
	}
	
} g;

void dfs0(int u) {
	dep[u]=dep[fa[u]]+1,siz[u]=1,son[u]=0;
	EDGE(g,i,u,v)if(v^fa[u])fa[v]=u,dfs0(v),siz[u]+=siz[v],son[u]=(siz[v]>siz[son[u]]?v:son[u]);
}

void dfs1(int u) {
	dfn[dl[u]=++idx]=u;
	if(son[u])top[son[u]]=top[u],dfs1(son[u]);
	EDGE(g,i,u,v)if(v!=fa[u]&&v!=son[u])top[v]=v,dfs1(v);
	dr[u]=idx;
}

int lca(int u,int v) {
	for(; top[u]^top[v]; v=fa[top[v]]) {
		if(dep[top[u]]>dep[top[v]])swap(u,v);
	}
	return dep[u]<dep[v]?u:v;
}

int dis(int u,int v) {
	return (dep[u]+dep[v])-(dep[lca(u,v)]<<1);
}

namespace Subtask1 {
	constexpr int N(5e2+10),lN(17),lV(lN+1);
	bool vis[N];
	int idx[N];
	int fa[M][lV];
	vector<int> Fa[N];

	bool Check() {
		return n<=500&&m<=500;
	}

	template<const bool ty>void Rebuild(int u) {
		fa[u][0]=::fa[u];
		FOR(i,1,lN)fa[u][i]=fa[fa[u][i-1]][i-1];
		EDGE(g,i,u,v)if(v!=fa[u][0]&&v!=son[u])Rebuild<0>(v);
		if(son[u])Rebuild<1>(son[u]);
		EDGE(g,i,u,v)if(v!=fa[u][0]&&v!=son[u])FOR(j,dl[v],dr[v])vis[dfn[j]]=1;
		vis[u]=1;
		Fa[u]=vector<int>(siz[u]+1,0);
		int tot(0);
		FOR(i,1,n)idx[i]=(vis[i]?++tot:0);
		FOR(i,1,n)if(vis[i])Fa[u][idx[i]]=idx[fa[i][0]];
		if(!ty)FOR(i,dl[u],dr[u])vis[dfn[i]]=0;
	}

	void Update(int u) {
		dep[u]=dep[fa[u][0]]+1;
		FOR(i,1,lN)fa[u][i]=fa[fa[u][i-1]][i-1];
		EDGE(g,i,u,v)if(v^fa[u][0])Update(v);
	}

	int lca(int u,int v) {
		if(dep[u]>dep[v])swap(u,v);
		DOR(i,lN,0)if((dep[v]-dep[u])&1<<i)v=fa[v][i];
		if(u==v)return u;
		DOR(i,lN,0)if(fa[u][i]^fa[v][i])u=fa[u][i],v=fa[v][i];
		return fa[u][0];
	}

	int dis(int u,int v) {
		return (dep[u]+dep[v])-(dep[lca(u,v)]<<1);
	}

	int Cmain() {
		Rebuild<0>(1);
		FOR(i,1,m) {
			int u,pa,rt(0);
			I(u,pa);
			FOR(j,1,Fa[u].size()-1)g.att(fa[n+j][0]=(Fa[u][j]?n+Fa[u][j]:(rt=n+j,pa)),n+j);
			Update(rt),n+=siz[u];
		}
		FOR(i,1,Q) {
			int u,v;
			I(u,v),O(dis(u,v),'\n');
		}
		return 0;
	}

}

namespace Subtask2 {
	constexpr int N(3e3+10),M(1e5+10),lN(16),lV(lN+1);
	bool vis[N];
	int tot;
	int rt[M],ty[M],rdep[M],mi[N],xFa[M];
	int Fa[M][lV],dFa[M][lV];
	vector<int> Dep[N],Idx[N];
	
	bool Check() {
		return n<=3000;
	}
	
	template<const bool ty>void Rebuild(int u) {
		EDGE(g,i,u,v)if(v!=fa[u]&&v!=son[u])Rebuild<0>(v);
		if(son[u])Rebuild<1>(son[u]);
		EDGE(g,i,u,v)if(v!=fa[u]&&v!=son[u])FOR(j,dl[v],dr[v])vis[dfn[j]]=1;
		vis[u]=1;
		int tot(0);
		Dep[u]=vector<int>(siz[u]+1,0),Idx[u]=vector<int>(siz[u]+1,0);
		FOR(i,1,n)if(vis[i])Dep[u][++tot]=dep[i]-dep[u]+1,Idx[u][tot]=i,mi[u]=(i==u?tot:mi[u]);
		if(!ty)FOR(i,dl[u],dr[u])vis[dfn[i]]=0;
	}
	
	int Root(int idx) {
		return upper_bound(rt+1,rt+tot+1,idx)-rt-1;
	}
	
	int Dis(int u,int v) {
		int x(Root(u)),y(Root(v)),ans(0);
		if(x==y)return dis(Idx[ty[x]][u-rt[x]+1],Idx[ty[y]][v-rt[y]+1]);
		if(rdep[x]>rdep[y])swap(u,v),swap(x,y);
		if(rdep[x]<rdep[y])ans+=Dep[ty[y]][v-rt[y]+1]-1,v=rt[y]+mi[ty[y]]-1;
		DOR(i,lN,0)if(rdep[Fa[y][i]]>rdep[x])ans+=dFa[y][i],y=Fa[y][i],v=rt[y]+mi[ty[y]]-1;
		if(Fa[y][0]==x)return v=xFa[y],y=Fa[y][0],ans+1+dis(Idx[ty[x]][u-rt[x]+1],Idx[ty[y]][v-rt[y]+1]);
		if(rdep[y]>rdep[x])v=xFa[y],y=Fa[y][0],++ans;
		ans+=Dep[ty[y]][v-rt[y]+1]-1,v=rt[y]+mi[ty[y]]-1,ans+=Dep[ty[x]][u-rt[x]+1]-1,u=rt[x]+mi[ty[x]]-1;
		DOR(i,lN,0)if(Fa[x][i]^Fa[y][i])
			ans+=dFa[x][i]+dFa[y][i],x=Fa[x][i],y=Fa[y][i],u=rt[x]+mi[ty[x]]-1,v=rt[y]+mi[ty[y]]-1;
		u=xFa[x],v=xFa[y],x=Fa[x][0],y=Fa[y][0];
		return ans+2+dis(Idx[ty[x]][u-rt[x]+1],Idx[ty[y]][v-rt[y]+1]);
	}
	
	int Cmain() {
		rt[tot=1]=ty[1]=rdep[1]=1,Rebuild<0>(1);
		FOR(i,1,m) {
			int u,pa,Pa;
			I(u,pa),Pa=Root(pa),rt[++tot]=n+1,n+=siz[ty[tot]=u],rdep[tot]=rdep[Pa]+1,xFa[tot]=pa;
			Fa[tot][0]=Pa,dFa[tot][0]=Dep[ty[Pa]][pa-rt[Pa]+1];
			FOR(j,1,lN)Fa[tot][j]=Fa[Fa[tot][j-1]][j-1];
			FOR(j,1,lN)dFa[tot][j]=dFa[tot][j-1]+dFa[Fa[tot][j-1]][j-1];
		}
		FOR(i,1,Q) {
			int u,v;
			I(u,v),O(Dis(u,v),'\n');
		}
		return 0;
	}
	
}

int main() {
#ifdef Plus_Cat
	freopen(Plus_Cat ".in","r",stdin),freopen(Plus_Cat ".out","w",stdout);
#endif
	I(n,m,Q),g.Init();
	FOR(i,2,n) {
		int u,v;
		I(u,v),g.con(u,v);
	}
	dfs0(1),top[1]=1,dfs1(1);
	if(Subtask1::Check())return Subtask1::Cmain();
	if(Subtask2::Check())return Subtask2::Cmain();
	return 0;
}

\(100\%\)

考虑把预处理去掉,用数据结构代替,可以选择可持久化线段树,转化为区间第 \(k\) 小问题。

复杂度 \(O((Q+n+m)(\log_2{n}+\log_2{m}))\) 之类。

//#define Plus_Cat ""
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define LINF 0x3f3f3f3f
#define ll long long
#define RCL(a,b,c,d) memset(a,b,sizeof(c)*(d))
#define tomin(a,...) ((a)=min({(a),__VA_ARGS__}))
#define tomax(a,...) ((a)=max({(a),__VA_ARGS__}))
#define FOR(i,a,b) for(int i(a); i<=(int)(b); ++i)
#define DOR(i,a,b) for(int i(a); i>=(int)(b); --i)
#define EDGE(g,i,x,y) for(int i(g.h[x]),y(g[i].v); ~i; y=g[i=g[i].nxt].v)
using namespace std;
constexpr int N(1e5+10),lN(16),lV(lN+1);

namespace IOEcat {
#define isD(c) ('0'<=(c)&&(c)<='9')
#define DE(...) E(#__VA_ARGS__,__VA_ARGS__)
	struct Icat {

		char getc() {
			return getchar();
		}

		template<class T>void operator ()(T &x) {
			static bool sign(0);
			static char ch(0);
			sign=0,x=0;
			while(ch=getc(),!isD(ch))if(ch=='-')sign=1;
			do x=(x<<1)+(x<<3)+(ch^48);
			while(ch=getc(),isD(ch));
			if(sign)x=-x;
		}

		template<class T,class...Types>void operator ()(T &x,Types&...args) {
			return (*this)(x),(*this)(args...);
		}

	} I;
	struct Ocat {

		void putc(char c) {
			putchar(c);
		}

		template<class T>void operator ()(T x,const char lst='\n') {
			static int top(0);
			static char st[100];
			if(x<0)x=-x,putc('-');
			do st[++top]=(x%10)^48,x/=10;
			while(x);
			while(top)putc(st[top--]);
			putc(lst);
		}

		template<class T,class...Types>void operator ()(const T x,const char lst='\n',const Types...args) {
			return (*this)(x,lst),(*this)(args...);
		}

	} O;
	struct Ecat {

		template<class T>void operator ()(const char *fmt,const T x) {
			cerr<<fmt<<':'<<x<<'.'<<endl;
		}

		template<class T,class...Types>void operator ()(const char *fmt,const T x,const Types...args) {
			while(*fmt^',')cerr<<*fmt++;
			return cerr<<':'<<x<<" ,",(*this)(++fmt,args...);
		}

	} E;

} using namespace IOEcat;

int n,m,Q,idx,tot;
int dl[N],dr[N],fa[N],dep[N],dfn[N],siz[N],son[N],top[N];
ll cnt;
struct CFS {
	int tot,h[N];
	struct edge {
		int v,nxt;
		
		edge(int v=0,int nxt=-1):v(v),nxt(nxt) {}
		
	} e[N<<1];
	
	edge &operator [](int i) {
		return e[i];
	}
	
	void Init() {
		tot=-1,RCL(h,-1,h,1);
	}
	
	void att(int u,int v) {
		e[++tot]=edge(v,h[u]),h[u]=tot;
	}
	
	void con(int u,int v) {
		att(u,v),att(v,u);
	}
	
} g;
struct PSEG {
	int tot,rt[N];
	struct node {
		int ls,rs,sum;
		
		node(int ls=0,int rs=0,int sum=0):ls(ls),rs(rs),sum(sum) {}
		
	} tr[N*lV];
	
	int &operator [](int i) {
		return rt[i];
	}
#define ls(p) (tr[p].ls)
#define rs(p) (tr[p].rs)
#define mid ((l+r)>>1)
	void Plus(int x,int &p,int q,int l=1,int r=n) {
		tr[p=++tot]=tr[q],++tr[p].sum;
		if(l==r)return;
		return x<=mid?Plus(x,ls(p),ls(q),l,mid):Plus(x,rs(p),rs(q),mid+1,r);
	}
	
	int BS(int k,int p,int q,int l=1,int r=n) {
		if(l==r)return l;
		if(k<=tr[ls(q)].sum-tr[ls(p)].sum)return BS(k,ls(p),ls(q),l,mid);
		return BS(k-(tr[ls(q)].sum-tr[ls(p)].sum),rs(p),rs(q),mid+1,r);
	}
	
	int Sum(int L,int R,int p,int q,int l=1,int r=n) {
		if(L<=l&&r<=R)return tr[q].sum-tr[p].sum;
		if(R<=mid)return Sum(L,R,ls(p),ls(q),l,mid);
		if(mid<L)return Sum(L,R,rs(p),rs(q),mid+1,r);
		return Sum(L,R,ls(p),ls(q),l,mid)+Sum(L,R,rs(p),rs(q),mid+1,r);
	}
#undef ls
#undef rs
#undef mid
} seg;

void dfs0(int u) {
	dep[u]=dep[fa[u]]+1,siz[u]=1,son[u]=0;
	EDGE(g,i,u,v)if(v^fa[u])fa[v]=u,dfs0(v),siz[u]+=siz[v],son[u]=(siz[v]>siz[son[u]]?v:son[u]);
}

void dfs1(int u) {
	dfn[dl[u]=++idx]=u;
	if(son[u])top[son[u]]=top[u],dfs1(son[u]);
	EDGE(g,i,u,v)if(v!=fa[u]&&v!=son[u])top[v]=v,dfs1(v);
	dr[u]=idx;
}

int lca(int u,int v) {
	for(; top[u]^top[v]; v=fa[top[v]]) {
		if(dep[top[u]]>dep[top[v]])swap(u,v);
	}
	return dep[u]<dep[v]?u:v;
}

struct Tree {
	int ty,Depth;
	ll pa,rt,mi,depth;
	int fa[lV];
	
	int &operator [](int i) {
		return fa[i];
	}
	
	int idx(ll k) {
		return seg.BS(k-mi+1,seg[dl[ty]-1],seg[dr[ty]]);
	}
	
	ll rev(int k) {
		return mi+seg.Sum(1,k,seg[dl[ty]-1],seg[dr[ty]])-1;
	}
	
	ll Dep(ll k) {
		return depth+(dep[idx(k)]-dep[ty]+1)-1;
	}
	
} a[N];

int Idx(ll k) {
	int ans(0);
	for(int l(1),r(tot),mid((l+r)>>1); l<=r; mid=(l+r)>>1)a[mid].mi<=k?ans=mid,l=mid+1:r=mid-1;
	return ans;
}

void Build(int ty,ll pa,Tree &A) {
	A.ty=ty,A.pa=pa,A.rt=cnt+seg.Sum(1,ty,seg[dl[ty]-1],seg[dr[ty]]),A.mi=cnt+1,cnt+=siz[ty];
	A.depth=a[A[0]=Idx(pa)].Dep(pa)+1,A.Depth=a[A[0]].Depth+1;
	FOR(i,1,lN)A[i]=a[A[i-1]][i-1];
}

ll Lca(ll u,ll v) {
	int x(Idx(u)),y(Idx(v));
	if(x==y)return a[x].rev(lca(a[x].idx(u),a[y].idx(v)));
	if(a[x].Depth>a[y].Depth)swap(x,y),swap(u,v);
	DOR(i,lN,0)if(a[a[y][i]].Depth>a[x].Depth)v=a[y=a[y][i]].rt;
	if(a[y][0]==x)return v=a[y].pa,y=a[y][0],a[x].rev(lca(a[x].idx(u),a[y].idx(v)));
	if(a[y].Depth>a[x].Depth)v=a[y=a[y][0]].rt;
	DOR(i,lN,0)if(a[x][i]^a[y][i])x=a[x][i],y=a[y][i];
	u=a[x].pa,v=a[y].pa,x=a[x][0],y=a[y][0];
	return a[x].rev(lca(a[x].idx(u),a[y].idx(v)));
}

ll Dep(ll k) {
	return a[Idx(k)].Dep(k);
}

ll Dis(ll u,ll v) {
	return (Dep(u)+Dep(v))-(Dep(Lca(u,v))<<1);
}

int main() {
#ifdef Plus_Cat
	freopen(Plus_Cat ".in","r",stdin),freopen(Plus_Cat ".out","w",stdout);
#endif
	I(n,m,Q),g.Init(),cnt=n;
	FOR(i,2,n) {
		int u,v;
		I(u,v),g.con(u,v);
	}
	dfs0(1),top[1]=1,dfs1(1);
	FOR(i,1,n)seg.Plus(dfn[i],seg[i],seg[i-1]);
	a[tot=1]= {1,1,1,1,1,1,{}};
	FOR(i,1,m) {
		int ty;
		ll pa;
		I(ty,pa),Build(ty,pa,a[++tot]);
	}
	FOR(i,1,Q) {
		ll u,v;
		I(u,v),O(Dis(u,v),'\n');
	}
	return 0;
}
posted @ 2025-01-22 10:38  Add_Catalyst  阅读(8)  评论(0)    收藏  举报