Yoi #316. 最近公共祖先

题面


分析

如果i+1在i的子树内,则i+1的答案也在i的子树内,否则不行

可以通过类似并查集的方法实现,之后树上差分

#include<bits/stdc++.h>
using namespace std;

const int N=3e6+5;
int n,cnt,to[N<<1],nxt[N<<1],he[N],t[N],in[N],out[N],sgn,f[N];

inline void add(int u,int v) {
	to[++cnt]=v,nxt[cnt]=he[u],he[u]=cnt;
}

void dfs(int fa,int u) {
	in[u]=++sgn;
	for(int e=he[u];e;e=nxt[e]) {
		int v=to[e];
		if(v!=fa) {
			dfs(u,v);
		}
	}
	out[u]=sgn;
}

int find(int x) {
	return x==f[x]?x:f[x]=find(f[x]);
}
int main() {
	freopen("ancestor.in","r",stdin);
	freopen("ancestor.out","w",stdout);
	scanf("%d",&n);
	for(int i=2;i<=n;i++) {
		int u; scanf("%d",&u);
		add(u,i),add(i,u);
	}
	for(int i=1;i<=n;i++) f[i]=i;
	dfs(0,1);
	for(int i=n;i>=1;i--) {
		int j=i;
		while(j+1<=n&&in[i]<=in[j+1]&&in[j+1]<=out[i]) {
			f[j]=j+1,j=find(j);
		}
		t[i]++,t[j+1]--;
	}
	int ans=0;
	for(int i=1;i<=n;i++) {
		ans+=t[i]; printf("%d\n",ans);
	}
	return 0;
}

posted @ 2020-10-25 19:27  wwwsfff  阅读(56)  评论(0)    收藏  举报