題目
題目鏈接:https://codeforces.com/problemset/problem/1528/C
給定兩棵大小為 \(n\) 的樹,以及 \(n\) 個點,點 \(x,y\) 之間會有連邊當且僅當 \(x,y\) 在第一棵樹上為祖孫關系,且在第二棵樹上不是祖孫關系。
求圖的最大團。多測。
\(Q,\sum n\leq 3\times 10^5\)。
思路
oisdoaiu CCCCCCCCOrz。
等價於在第一棵樹上 \(1\) 到 \(x\) 的一條鏈上的所有點,選盡量多滿足它們在第二棵樹上的子樹不交。
在第一棵樹上 dfs,當搜索到點 \(x\) 的時候,如果選出的祖先中有一個與 \(x\) 的子樹有交集,肯定選擇孫子最優。
又因為題目保證每一個節點的父親編號比他小,所以等價於肯定選 \(x\)。
那么我們需要實現的就是區間覆蓋,單點查詢,直接用樹狀數組維護即可。
時間復雜度 \(O(n\log 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\n",ans);
}
int main()
{
scanf("%d",&Q);
while (Q--) work();
return 0;
}