[bzoj] 2851: 极限满月

2 篇文章 0 订阅
2 篇文章 0 订阅

这道题初看时没想到过树,看了题解才知道可以建虚树

对题目分析可以将b数组想成一颗树,第i个b数组就是点i到根节点的上路径的所有点的集合。

那么在构造树时就相当于将a数组中的所有点取lca ,再将i节点连到lca上,作为lca的儿子。

这样的复杂度是O(nlogn)的。

在询问时离线处理,dfs更新每个点对问题的贡献。

其深度减去lca的深度即为贡献。

#include <cstdio>
#include <vector>
#include <cstring>
using namespace std;
const int N=200005;
struct node {
	int len;
	vector<int> to;
}a[N],que[N];
int n,m,lca;
int fa[N][20];
int dep[N];
vector <int> son[N];
int sig[N];
int ans[N];
inline int getlca(int x,int y)
{
	int p,st=0;
	if (dep[x]<dep[y]) p=x,x=y,y=p;
	p=dep[x]-dep[y];
	while (p)
	{
		if (p&1) x=fa[x][st];
		p/=2,st++;
	}
	st=0;
	while (x!=y)
	{
		if (fa[x][st]!=fa[y][st]||(fa[x][st]==fa[y][st])&&!st)
		{
			x=fa[x][st];
			y=fa[y][st];
			st++;
		}
		else st--;
	}
	return x;
}
void dfs(int x)
{
	int i;
	for (i=0;i<que[x].to.size();i++)
	{
		if (sig[que[x].to[i]]==-1)
		{
			ans[que[x].to[i]]+=dep[x];
			sig[que[x].to[i]]=x;
		}
		else 
		{
			ans[que[x].to[i]]+=dep[x]-dep[getlca(x,sig[que[x].to[i]])];
			sig[que[x].to[i]]=x;
		}
	}
	for (i=0;i<son[x].size();i++) dfs(son[x][i]);
}
int main()
{
	register int i,j;
	scanf("%d",&n);
	int x,st;
	for (i=1;i<=n;i++)
	{
		scanf("%d",&a[i].len);
		for (j=1;j<=a[i].len;j++)
		scanf("%d",&x),a[i].to.push_back(x);
	}
	dep[0]=1;
	for (i=1;i<=n;i++)
	{
		if (!a[i].len)
		{
			fa[i][0]=0;
			dep[i]=dep[0]+1;
			son[0].push_back(i);
			continue;
		}
		lca=a[i].to[0];
		for (j=1;j<a[i].len;j++) lca=getlca(lca,a[i].to[j]);
		son[lca].push_back(i);dep[i]=dep[lca]+1;
		st=0;fa[i][st]=lca;
		while (fa[i][st]) fa[i][st+1]=fa[fa[i][st]][st],st++;
	}
	scanf("%d",&m);
	for (i=1;i<=m;i++)
	{
		scanf("%d",&que[i].len);
		for (j=1;j<=que[i].len;j++)
		scanf("%d",&x),que[x].to.push_back(i);
	}
	memset(sig,-1,sizeof(sig));
	dfs(0);
	for (i=1;i<=m;i++)
	printf("%d\n",ans[i]-1);
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值