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;
}
浙公网安备 33010602011771号