CF208E Blood Cousins

题面

Blood Cousins - 洛谷

题目大意:

给出一个n个点的森林,m次询问,每次求一个点的k级亲戚的数量

k级亲戚定义为,u≠v,u,v的k级祖先相同,则u,v为k级亲戚

题解

一定仔细读题md,是k级祖先,不是LCA为k级祖先

我的做法是先倍增求点u的k级祖先

然后统计k级祖先下深度为dep[u]点的个数

想来想去没想到好方法,然后就dfs序+莫队莽过去了

后来发现可以线段树合并,dsu on tree,每个点开一个线段树,

然后把询问挂在点上,遍历一遍,一个一个合并线段树,合并完之后做查询记录答案。

再后来发现dfs序+主席树可以在线。

代码(莫队):

#include
#include
#include
using namespace std;
inline int gi()
{
	int num=0,flg=1;char c;
	while((c=getchar())<'0'||c>'9')if(c=='-')flg=-1;
	while(c>='0'&&c<='9'){num=num*10+c-48;c=getchar();}
	return num*flg;
}
#define N 100005
#define LOG 17
#define D 310
int fir[N],to[2*N],nxt[2*N],cnt;
int fa[N][LOG+2];
int getk(int x,int k)
{
	for(int i=LOG;i>=0;i--)
		if(k&(1<t.r)));
	}
}q[N];
int depcnt[N];
int ans[N];
int main()
{
	int n,m,i,j,x,v,k;
	n=gi();
	for(i=1;i<=n;i++){
		fa[i][0]=gi();
		adde(fa[i][0],i);
	}
	for(j=1;j<=LOG;j++)
		for(i=1;i<=n;i++)
			fa[i][j]=fa[fa[i][j-1]][j-1];
	for(i=1;i<=n;i++)
		if(!fa[i][0])dfs(i,0);
	m=gi();
	for(i=1;i<=m;i++){
		v=gi();k=gi();
		x=getk(v,k);
		if(x!=0){
			q[++qcnt].l=dfn[x];
			q[qcnt].r=dfn[x]+siz[x]-1;
			q[qcnt].k=dep[v];
			q[qcnt].flg=1;
			q[qcnt].id=i;
		}
	}
	sort(q+1,q+qcnt+1);
	int l=1,r=0;
	for(i=1;i<=qcnt;i++){
		while(rq[i].l){
			l--;
			depcnt[dep[num[l]]]++;
		}
		while(lq[i].r){
			depcnt[dep[num[r]]]--;
			r--;
		}
		ans[q[i].id]+=depcnt[q[i].k]*q[i].flg;
	}
	for(i=1;i<=m;i++){
		if(ans[i])
			printf("%d ",ans[i]-1);
		else
			printf("0 ");;
	}
}

你可能感兴趣的:(算法,莫队,深度优先,启发式算法)