gmoj 7065. 【2021.4.24 NOI模拟】樟树
这道题的 n 很小,很容易联想到用回滚莫队解决。
那么怎么分块呢?
对于一棵 𝑛 个点的有根树,取\(\sqrt n\)级别个关键点,使每个关键点的子树内离它最近的关键点距离<=\(\sqrt n\),这个可以从下往上贪心。
使用可回撤并查集计算答案。
然后我们考虑怎么计算每个块 ( 就是每个关键点除去其子树内关键点的子树后剩下的点 ),发现可以先把第一棵树算出关键点,按这些关键点的 dfs 序处理每个块,这样的话关键点与关键点之间的转移总共O( n ),对于每个块,把块内的点按第二棵树的 dfs 序排序处理,对于每个块,遍历一遍第二棵树,每遇到块内的点,就在第一颗树上加入某条链上的点,得到答案后再撤回关键点。这样做总时间复杂度显然是O( \(n\) \(\sqrt n\) ) 级别的。
附上代码
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
const int N=51000;
struct yz{int x,y;}a[N],b[N],z[N];
struct zy{int to,ne;}e[N*2],g[N*2];
struct zz{int co,id;}c[N];
int we[N],wg[N],f[N],dfe[N],dfg[N],bz[N],s[N],fa[N],w[N];
int h[N],t[N][2],p[N],an[N];
int T,n,m,d,l,r,x,y,i,j,tm,u,v,ff,ss;
inline int read(){
	int x=0; char c=getchar();
	while(c<'0'||c>'9') c=getchar();
	while('0'<=c&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
	return x;
}
inline void ad1(int x,int y){e[++l]=(zy){y,we[x]}; we[x]=l;}
inline void ad2(int x,int y){g[++l]=(zy){y,wg[x]}; wg[x]=l;}
inline int cmp(zz x,zz y){return dfg[x.id]<dfg[y.id];}
inline int cmp1(zz x,zz y){return x.co<y.co;}
inline int max(int x,int y){return x>y ? x:y;}
void dfse(int x,int la){
	int i,y; f[x]=1; dfe[x]=++r;
	for(i=we[x];i;i=e[i].ne){
		y=e[i].to;
		if (y==la) continue;
		fa[y]=x; dfse(y,x);
		f[x]=max(f[x],f[y]+1); s[x]+=s[y];
	}
	if (f[x]>d||x==1) f[x]=1,bz[x]=1,s[x]++;
}
void dfsg(int x,int la){
	dfg[x]=++r;
	for(int i=wg[x];i;i=g[i].ne)
		if (g[i].to!=la) dfsg(g[i].to,x);
}
void dfs1(int x,int la){
	int i,no=l;
	if (bz[x]) l++,w[l]=x;
	c[x].co=l; c[x].id=x;
	for(i=we[x];i;i=e[i].ne)
		if (e[i].to!=la) dfs1(e[i].to,x);
	l=no;
}
inline int gf(int x){
	while(h[x]!=x) x=h[x];
	return x;
}
inline void ad(int v,int z){
	int x,y,fx,fy; tm++;
	if (!z) x=a[v].x,y=a[v].y;
	else x=b[v].x,y=b[v].y;
	fx=gf(x); fy=gf(y);
	if (fx!=fy){
		t[++r][0]=tm;
		if (p[fx]<p[fy]) h[fx]=fy,p[fy]+=p[fx],t[r][1]=fx;
		else h[fy]=fx,p[fx]+=p[fy],t[r][1]=fy;
		ss--;
	}
}
inline void de(int tt){
	int x;
	while(r>0&&t[r][0]>=tt){
		x=t[r][1];
		p[h[x]]-=p[x]; h[x]=x; ss++; r--;
	}
}
void dfs3(int x,int la){
	int i,y;
	if (u>v) return;
	ad(x,1); int no=tm;
	if (u<=v&&c[u].id==x){
		y=x;
		while(y!=ff) ad(y,0),y=fa[y];
		an[x]=ss;
		de(no+1);
		u++;
	}
	for(i=wg[x];i;i=g[i].ne)
		if (g[i].to!=la) dfs3(g[i].to,x);
	de(no);
}
void dfs2(int x,int la){
	int i;
	ad(x,0); int no=tm;
	if (bz[x]){
		ff=x;
		u=z[x].x;
		v=z[x].y;
		dfs3(1,0);
	}
	for(i=we[x];i;i=e[i].ne)
		if (e[i].to!=la&&s[e[i].to]) dfs2(e[i].to,x);
	de(no);
}
int main(){
	int size=128<<20;
	char *p1=(char*)malloc(size)+size;
	__asm__("movq %0, %%rsp\n" :: "r"(p1));
	freopen("camphor.in","r",stdin);
	freopen("camphor.out","w",stdout);
	for(T=read();T;--T){
		n=read(); m=read(); d=sqrt(n); tm=0; ss=m;
		for(i=1;i<=n;++i)
			we[i]=wg[i]=bz[i]=s[i]=w[i]=0;
		for(i=1;i<=m;++i)
			h[i]=i,p[i]=1;
		for(i=1;i<=n;++i)
			a[i].x=read(),a[i].y=read();
		l=0;
		for(i=1;i<n;++i)
			x=read(),y=read(),ad1(x,y),ad1(y,x);
		for(i=1;i<=n;++i)
			b[i].x=read(),b[i].y=read();
		l=0;
		for(i=1;i<n;++i)
			x=read(),y=read(),ad2(x,y),ad2(y,x);
		r=0; dfse(1,0);
		r=0; dfsg(1,0);
		l=0; dfs1(1,0);
		sort(c+1,c+n+1,cmp1);
		for(i=1;i<=n;i=j+1){
			j=i; while(j<n&&c[j+1].co==c[i].co) j++;
			z[w[c[i].co]].x=i;
			z[w[c[i].co]].y=j;
			sort(c+i,c+j+1,cmp);
		}
		
		r=0; dfs2(1,0);
		for(i=1;i<=n;++i)
			printf("%d\n",an[i]);
	}
	exit(0);
}

 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号