题意:给定两颗以1为根n个点的树,问你最大的集合S,满足S中的任意两个元素在第一颗树上必有一个点是另一个点的祖先,且要是连续的一些点,在第二颗树上都不是对方的祖先。
1<=n<=3e5
第一个条件可以看出来是一条链,对于第二个条件如果选了一个点,那么其子树一定不能选。所以我们可以dfs序处理一下,则选了一个点u我们就将其在线段树上
[
i
n
[
u
]
,
o
u
t
[
u
]
]
[in[u],out[u]]
[in[u],out[u]]覆盖,如果有重复覆盖的那么一定是两者只能取其一,可以遍历第一颗树然后用线段树来维护,线段树里面存遍历路径上的深度最大值,那么答案
a
n
s
=
m
a
x
(
a
n
s
,
d
[
u
]
−
d
i
s
)
ans=max(ans,d[u]-dis)
ans=max(ans,d[u]−dis),dis为到当前结点且有重复覆盖的最大深度。
因为线段树上面有覆盖且有回溯,所以除了可持久化还可以建立vector来维护线段树,vector里面存当前区间所有的深度,如果这段区间被覆盖就
p
u
s
h
_
b
a
c
k
push\_back
push_back进去,否则就
p
o
p
_
b
a
c
k
pop\_back
pop_back出来。因为是取max所以可以不用写pushdown,直接在查询的时候取个max即可。
很多题解是用双指针,如果上面的点与该点矛盾,则在线段树上修改这个值,不断将上面的点往下移,然后在回溯的时候再一个一个往上跳修改,这个复杂度其实是O(
n
2
l
o
g
n
n^2logn
n2logn)的,因为第一颗树如果是n/2个点都在一条链上,然后n/2个点以这个链的末尾为父亲结点,这样就会被卡掉,每个点的更新都会移动2*n/2次,所以总共移动
n
∗
n
/
2
n*n/2
n∗n/2次。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=3e5+10;
vector<int>G1[maxn],G2[maxn];
int k,in[maxn],out[maxn];
void dfs(int u,int fa)
{
in[u]=++k;
for(auto v:G2[u])
{
if(v==fa) continue;
dfs(v,u);
}
out[u]=k;
}
vector<int>tree[maxn*4];
int d[maxn],mx[maxn*4];
void pushup(int l,int r,int x)
{
mx[x]=0;
if(tree[x].size()) mx[x]=tree[x].back(); //可能子节点的深度比x更大 这里取max没有用pushdown
if(l==r) return ; //根节点
mx[x]=max(mx[x],mx[x<<1]);
mx[x]=max(mx[x],mx[x<<1|1]);
}
void modify(int l,int r,int x,int st,int ed,int c) //维护max
{
if(st<=l&&r<=ed) {
if(c>0) tree[x].push_back(d[c]);
else tree[x].pop_back();
pushup(l,r,x);
return ;
}
int mid=l+r>>1;
if(mid>=st) modify(l,mid,x<<1,st,ed,c);
if(mid<ed) modify(mid+1,r,x<<1|1,st,ed,c);
pushup(l,r,x);
}
int query(int l,int r,int x,int st,int ed) //询问[st,ed]的最大深度
{
if(st<=l&&r<=ed) return mx[x];
int mid=l+r>>1;
int ans=0;
if(tree[x].size()) ans=tree[x].back(); //没有用pushdown
if(mid>=st) ans=max(ans,query(l,mid,x<<1,st,ed));
if(mid<ed) ans=max(ans,query(mid+1,r,x<<1|1,st,ed));
return ans;
}
int ans=1;
void dfs1(int u,int fa,int dis) //dis表示上一结点矛盾最大深度
{
dis=max(dis,query(1,k,1,in[u],out[u])); //与当前结点矛盾最大深度
ans=max(ans,d[u]-dis);
modify(1,k,1,in[u],out[u],u);
for(auto v:G1[u])
{
if(v==fa) continue;
d[v]=d[u]+1;
dfs1(v,u,dis);
}
modify(1,k,1,in[u],out[u],-1);
}
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int t;cin>>t;
while(t--)
{
int n;cin>>n;
for(int i=1;i<=n;i++)
G1[i].clear(),G2[i].clear();
for(int i=1;i<n;i++)
{
int x,y;cin>>x>>y;
G1[x].push_back(y);
G1[y].push_back(x);
}
for(int i=1;i<n;i++)
{
int x,y;cin>>x>>y;
G2[x].push_back(y);
G2[y].push_back(x);
}
k=0;dfs(1,1);
ans=1;d[1]=1;
for(int i=1;i<=4*k;i++)
tree[i].clear(),mx[i]=0;
dfs1(1,1,0);
cout<<ans<<endl;
}
return 0;
}