【CF1528C】Trees of Tranquillity

题目

题目链接: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;
}
posted @ 2021-05-25 09:53  stoorz  阅读(291)  评论(0编辑  收藏  举报