题目
样例:
输入
3
5
2 1
2 5
5 3
2 4
2 1
1 5
1 3
3 4
5
5 3
3 1
5 4
3 2
5 3
5 1
3 4
3 2
5
5 3
5 1
5 2
5 4
5 3
3 1
5 2
3 4
输出
3
1
2
分析
- 选的点在第一棵树上是连续的一条链;而在第二棵树上是互不为祖先,即他们的子树不重叠。
- 那么令 ans[x] 为以 x 点为最末端的点,在第一棵树往上最长符合条件的链。在第一棵树上遍历,用双向队列记录集合中的点,然后对第二棵树的dfs序列维护区间即可。
- 具体操作见代码。
- 时间复杂度是 O(n lgn)。
代码
#include "bits/stdc++.h"
//#include <bitsdc++.h>
using namespace std;
#define MAXN (300010)
int a[MAXN<<2],lazy[MAXN<<2];
#define lchild(x) ((x)<<1)
#define rchild(x) (((x)<<1)|1)
void PushDown(int root,int L,int R)
{
lazy[lchild(root)] += lazy[root];
lazy[rchild(root)] += lazy[root];
a[lchild(root)] += lazy[root];
a[rchild(root)] += lazy[root];
lazy[root] = 0;
}
void Add(int root,int L,int R,int l,int r,int val)
{
if(l<=L&&R<=r)
{
a[root] += val;
lazy[root] += val;
return;
}
int M = (L + R) / 2;
if(l<=M)
Add(lchild(root), L, M, l, r, val);
if(r>M)
Add(rchild(root), M + 1, R, l, r, val);
a[root] = max(a[lchild(root)], a[rchild(root)]);
a[root] += lazy[root];
}
int Query(int root,int L,int R,int l,int r)
{
if(l<=L&&R<=r)
return a[root];
int maxnum = -MAXN;
PushDown(root, L, R);
int M = (L + R) / 2;
if(l<=M)
maxnum = max(maxnum, Query(lchild(root), L, M, l, r));
if(r>M)
maxnum = max(maxnum, Query(rchild(root), M + 1, R, l, r));
return maxnum;
}
int n;
int u1[MAXN],v1[MAXN],u2[MAXN],v2[MAXN];
int cnt[MAXN];
int curSet[MAXN],curL,curR;
int ans[MAXN];
int Lid[MAXN],Rid[MAXN];
int idcnt;
void dfsLRid(int X, int fX, vector<vector<int>> &G)
{
Lid[X]=++idcnt;
for (int o: G[X]) if (o!=fX)
dfsLRid(o,X,G);
Rid[X]=idcnt;
}
void ADD(int X)
{
Add(1, 0, n + 2, Lid[X], Rid[X], 1);
}
void DEL(int X)
{
Add(1, 0, n + 2, Lid[X], Rid[X], -1);
}
bool fail(int X)
{
return Query(1, 0, n + 2, Lid[X], Rid[X]) > 0;
}
void dfs(int X, int fX, vector<vector<int>> &GG)
{
int lstL=curL,lstR=curR;
while (curL<=curR && fail(X)) {
DEL(curSet[curL]);
curL++;
}
curR++;
curSet[curR]=X;
ADD(X);
ans[X]=curR-curL+1;
for (int o: GG[X]) if (o!=fX) {
dfs(o,X,GG);
}
while (curL>lstL) {
curL--;
ADD(curSet[curL]);
}
DEL(X);
curR=lstR;
}
void solve()
{
scanf("%d",&n);
vector<vector<int>> G1(n+1,vector<int>());
vector<vector<int>> G2(n+1,vector<int>());
for (int i=1; i<n; i++) scanf("%d %d",&u1[i],&v1[i]);
for (int i=1; i<n; i++) scanf("%d %d",&u2[i],&v2[i]);
for (int i=1; i<n; i++) {
G1[u1[i]].push_back(v1[i]);
G1[v1[i]].push_back(u1[i]);
}
for (int i=1; i<n; i++) {
G2[u2[i]].push_back(v2[i]);
G2[v2[i]].push_back(u2[i]);
}
idcnt=0;
dfsLRid(1,0,G2); //获得G2的dfs序,使得每个点的子树在序列中都是连续的一段区间
curL=1,curR=0;
dfs(1,0,G1); //遍历G1,处理答案
int ANS=0;
for (int i=1; i<=n; i++) {
ANS=max(ANS,ans[i]);
}
printf("%d\n",ANS);
}
int main()
{
int ttt;
scanf("%d",&ttt);
while (ttt--) {
solve();
}
return 0;
}