ANJHZ的博客

2021牛客暑期多校7-F-xay loves trees (dfs序+线段树+队列)

题意简单来讲就是在第一棵树上找一条链,使得这条链上每一对点在第二棵树上不构成祖先子孙关系。

性质1:如果u-v是树1上的一条链,其中u是v的祖先,且这条链不满足在第二棵树上的要求,那么fau-v同样不满足要求。因此可以考虑对于树1上的每个点v,找到深度最浅的满足题目要求的祖先u,两者深度相减就是v的答案。所有v的答案取max就是ans。

 

性质2:两个点构成祖先子孙关系当且仅当两者的子树有交。可以跑一遍dfs序,并且对每个要判断的点拿出它的子树([dfn,dfn+siz-1]),把子树里的所有点+1,最后所有点都这么搞完之后看一下全局的最大值是否大于等于2,若大于等于2,就说明存在两个点构成祖先子孙关系。

所以做法总结一下就是先对树2求dfs序,然后对树1dfs,每访问树1的一个点就把当前点入队,并且进行子树加1,然后{while(全局max>=2) 出队},出队的时候子树-1,ans=max(ans,队列元素数量)。

注意回溯前要在线段树上逆操作。

#include <bits/stdc++.h>
using namespace std;
const int N=3e5+11;
int n,t,top=-1,vis[2][N],dfn[N],siz[N],cnt,stk[N],head,tail,ans;
struct edge
{
	int to;
	edge *nest;
}e[N<<2],*v[2][N];
void addedge(int from,int to,int ver)
{
	e[++top].to=to;
	e[top].nest=v[ver][from];
	v[ver][from]=&e[top];
}
struct seg_tree
{
	int ma,pls;
}a[N<<2];
void pushdown(int now,int l,int r)
{
	if(l==r){a[now].pls=0;return;}
	int mid=(l+r)/2;
	a[now*2].ma+=a[now].pls;
	a[now*2+1].ma+=a[now].pls;
	a[now*2].pls+=a[now].pls;
	a[now*2+1].pls+=a[now].pls;
	a[now].pls=0;
}
void buildtree(int now,int l,int r)
{
	a[now].ma=a[now].pls=0;
	if(l==r) return;
	int mid=(l+r)/2;
	buildtree(now*2,l,mid);
	buildtree(now*2+1,mid+1,r);
}
void update(int now){a[now].ma=max(a[now*2].ma,a[now*2+1].ma);}
void modify(int now,int l,int r,int ll,int rr,int pls)
{
	if(ll>rr) return;
	pushdown(now,l,r);
	if(l==ll&&r==rr)
	{
		a[now].ma+=pls;
		a[now].pls+=pls;
		return;
	}
	int mid=(l+r)/2;
	if(rr<=mid) modify(now*2,l,mid,ll,rr,pls);
	else if(ll>mid) modify(now*2+1,mid+1,r,ll,rr,pls);
	else
	{
		modify(now*2,l,mid,ll,mid,pls);
		modify(now*2+1,mid+1,r,mid+1,rr,pls);
	}
	update(now);
}
int query(int now,int l,int r,int ll,int rr)
{
	pushdown(now,l,r);
	if(l==ll&&r==rr) return a[now].ma;
	int mid=(l+r)/2;
	if(rr<=mid) return query(now*2,l,mid,ll,rr);
	else if(ll>mid) return query(now*2+1,mid+1,r,ll,rr);
	else return max(query(now*2,l,mid,ll,mid),query(now*2,mid+1,r,mid+1,rr));
}
void dfs2(int now)
{
	vis[1][now]=1;
	dfn[now]=++cnt;
	edge* ne;
	siz[now]=1;
	for(ne=v[1][now];ne;ne=ne->nest)
	{
		if(!vis[1][ne->to])
		{
			dfs2(ne->to);
			siz[now]+=siz[ne->to];
		}
	}
}
void dfs1(int now)
{
	vis[0][now]=1;
	stk[++tail]=now;
	modify(1,1,n,dfn[now],dfn[now]+siz[now]-1,1);
	int befhead=head;
	while(tail>head&&query(1,1,n,1,n)>1) modify(1,1,n,dfn[stk[head]],dfn[stk[head]]+siz[stk[head]]-1,-1),head++;
	ans=max(ans,tail-head+1);
	int nowhead=head,nowtail=tail;
	edge* ne;
	for(ne=v[0][now];ne;ne=ne->nest)
	{
		if(!vis[0][ne->to])
		{
			dfs1(ne->to);
			head=nowhead,tail=nowtail;
		}
	}
	modify(1,1,n,dfn[now],dfn[now]+siz[now]-1,-1);
	for(int i=befhead;i<head;i++) modify(1,1,n,dfn[stk[i]],dfn[stk[i]]+siz[stk[i]]-1,1);
}
int main()
{
	int i,from,to;
	scanf("%d",&t);
	while(t--)
	{
		for(i=0;i<=top;i++) e[i].nest=NULL;
		for(i=1;i<=n;i++) v[0][i]=v[1][i]=NULL;
		top=-1;
		scanf("%d",&n);
		for(i=1;i<=n-1;i++)
		{
			scanf("%d%d",&from,&to);
			addedge(from,to,0);
			addedge(to,from,0);
		}
		for(i=1;i<=n-1;i++)
		{
			scanf("%d%d",&from,&to);
			addedge(from,to,1);
			addedge(to,from,1);
		}
		memset(vis,0,sizeof vis);
		cnt=0;
		dfs2(1);
		buildtree(1,1,n);
		head=1;tail=ans=0;
		dfs1(1);
		printf("%d\n",ans);
	}
	return 0;
}

  

 

posted on 2021-08-12 18:15  ANJHZ  阅读(71)  评论(0)    收藏  举报

导航