zjoi2012灾难

灾难、、、


这么恶心  4个小时

zjoi的时候也只有5个半小时啊


跪跪跪、、、、、、


哎  还是我太弱了、、、、、


topsort + lca

管他叫 ”灭绝树“



#include <cstring>
#include <cstdio>
#include <queue>
#define cle(a,b) memset(a,b,sizeof a)
using namespace std;
int n;
struct edge {
	int v,next;
}e[10000000];
int cnt;
int head[65538];
int thead[65538];
int HEAD[65538];
int t,u,v;
int fa[65538][17],depth[65538];
int cause[65538];
int ts[65538],in[65538];
queue<int>q;
void adde (int u,int v) {
	e[++cnt].v = v;
	e[cnt].next = thead[u];
	thead[u] = cnt;
	e[++cnt].v = u;
	e[cnt].next = head[v];
	head[v] = cnt;
}
void read () {
	cle(head,-1);
	cle(thead,-1);
	cle(HEAD,-1);
	scanf("%d",&n);
	for(int i = 1;i <= n;i++) {
		while(scanf("%d",&t),t) {
			adde(t,i);
			in[i]++;
		}
	}
}
void topsort () {
	t = 0;
	for(int i = 1;i <= n;i++)
		if(!in[i])
			q.push(i);
	while(!q.empty()) {
		u = q.front();
		q.pop();
		ts[++t] = u;
		for(int i = thead[u];i != -1;i = e[i].next) {
			v = e[i].v;
			in[v]--;
			if(!in[v])
				q.push(v);
		}
	}
}
void go_up (int &u,int d) {
	int temp = 16;
	while(d) {
		if((1 << temp) <= d) {
			d -= (1 << temp);
			u = fa[u][temp];
		}
		temp--;
	}
}
int lca (int u,int v) {
	if(depth[u] != depth[v])
		go_up(u,depth[u] - depth[v]);
	if(u == v)
		return u;
	int temp = 17;
	do {
		if(fa[u][--temp] != fa[v][temp]) {
			u = fa[u][temp];
			v = fa[v][temp];
		}
	}while(temp);
	return fa[v][0];
}
void ADDE (int u,int v) {
	e[++cnt].v = v;
	e[cnt].next = HEAD[u];
	HEAD[u] = cnt;
}
void build () {
	for(int i = 1;i <= n;i++) {
		t = -1;
		for(int j = head[ts[i]];j != -1;j = e[j].next) {
			if(t == -1)
				t = e[j].v;
			else t = lca( depth[t] > depth[e[j].v] ? t : e[j].v , depth[t] > depth[e[j].v] ? e[j].v : t );
		}
		fa[ts[i]][0] = t == -1 ? 0 : t;
		depth[ts[i]] = depth[t] + 1;
		ADDE(t,ts[i]);
		for(int j = 1;j <= 16;j++)
			fa[ts[i]][j] = fa[fa[ts[i]][j - 1]][j - 1];
	}
}
void dfs (int U) {
	for(int i = HEAD[U];i != -1;i = e[i].next) {
		dfs(e[i].v);
		cause[U] += cause[e[i].v] + 1;
	}
}
int main () {
	read();
	topsort();
	build();
	for(int i = 1;i <= n;i++)
		if(depth[i] == 1)
			dfs(i);
	for(int i = 1;i <= n;i++)
		printf("%d\n",cause[i]);
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值