题目
题目链接:https://codeforces.com/problemset/problem/1528/C
给定两棵大小为 (n) 的树,以及 (n) 个点,点 (x,y) 之间会有连边当且仅当 (x,y) 在第一棵树上为祖孙关系,且在第二棵树上不是祖孙关系。
求图的最大团。多测。
(Q,sum nleq 3 imes 10^5)。
思路
oisdoaiu CCCCCCCCOrz。
等价于在第一棵树上 (1) 到 (x) 的一条链上的所有点,选尽量多满足它们在第二棵树上的子树不交。
在第一棵树上 dfs,当搜索到点 (x) 的时候,如果选出的祖先中有一个与 (x) 的子树有交集,肯定选择孙子最优。
又因为题目保证每一个节点的父亲编号比他小,所以等价于肯定选 (x)。
那么我们需要实现的就是区间覆盖,单点查询,直接用树状数组维护即可。
时间复杂度 (O(nlog n))。
代码
#include <bits/stdc++.h>
using namespace std;
const int N=300010;
int Q,n,tot,ans,cnt,head[N],a[N],b[N],id[N],siz[N];
struct edge
{
int next,to;
}e[N];
void add(int from,int to)
{
e[++tot]=(edge){head[from],to};
head[from]=tot;
}
struct BIT
{
int c[N];
void add(int x,int v)
{
for (int i=x;i<=n;i+=i&-i)
c[i]+=v;
}
int query(int x)
{
int ans=0;
for (int i=x;i;i-=i&-i)
ans+=c[i];
return ans;
}
}bit;
void prework()
{
tot=ans=cnt=0;
for (int i=1;i<=n;i++)
head[i]=-1,bit.c[i]=0;
}
void dfs1(int x)
{
id[x]=++tot; siz[x]=1;
for (int i=head[x];~i;i=e[i].next)
dfs1(e[i].to),siz[x]+=siz[e[i].to];
}
void dfs2(int x)
{
int y=bit.query(id[x]);
if (y) bit.add(id[y],-y),bit.add(id[y]+siz[y],y);
else cnt++,ans=max(ans,cnt);
bit.add(id[x],x); bit.add(id[x]+siz[x],-x);
for (int i=head[x];~i;i=e[i].next)
dfs2(e[i].to);
bit.add(id[x],-x); bit.add(id[x]+siz[x],x);
if (y) bit.add(id[y],y),bit.add(id[y]+siz[y],-y);
else cnt--;
}
void work()
{
scanf("%d",&n);
for (int i=2;i<=n;i++) scanf("%d",&a[i]);
for (int i=2;i<=n;i++) scanf("%d",&b[i]);
prework();
for (int i=2;i<=n;i++) add(b[i],i);
tot=0; dfs1(1);
prework();
for (int i=2;i<=n;i++) add(a[i],i);
dfs2(1);
printf("%d
",ans);
}
int main()
{
scanf("%d",&Q);
while (Q--) work();
return 0;
}