HDU 4694: Important Sisters(支配树)




题意:

御坂和她的n-1个克隆姐姐(编号1~n-1)构成一张御坂网络,如果第x号"姐姐"和第y号"姐姐"有条x到y的有向边,则说明x可以将信息传给y,已知御坂妹妹作为n号点,是所有信息的源头,如果屏蔽掉x点之后y点无法得到御坂妹妹的信息,那么说明x是y的支配点,对于所有的点,求出它所有支配点的编号和(包括她自身的编号)

特殊的:如果x点本身就得不到信息,该点输出0


支配树模板题

Lengauer-Tarjan算法搞定

注意不用新建节点,直接将n作为支配树的根,对于在支配树中的点,答案就是该点到根的编号和,

对于不在支配树中的点,答案为0


模板:

#pragma comment(linker, "/STACK:102400000,102400000")
#include<stdio.h>
#include<vector>
#include<algorithm>
using namespace std;
#define LL long long
LL n, cnt, sdom[60005], idom[60005], key[60005], rak[60005];
LL dfn[60005], ufs[60005], fa[60005], val[60005];
vector<LL> G[60005], Gp[60005], Z[60005], Sp[60005];
LL Find(LL p)
{
	LL temp;
	if(ufs[p]==p)
		return p;
	temp = Find(ufs[p]);
	if(sdom[key[ufs[p]]]<sdom[key[p]])
		key[p] = key[ufs[p]];
	return ufs[p] = temp;
}
void Sech2(LL u)
{
	LL i, v;
	val[u] += u;
	for(i=0;i<Z[u].size();i++)
	{
		v = Z[u][i];
		val[v] += val[u];
		Sech2(v);
	}
}
void Sech(LL p)
{
	LL i, v;
	dfn[p] = sdom[p] = ++cnt;
	rak[cnt] = p;
	for(i=0;i<G[p].size();i++)
	{
		v = G[p][i];
		if(dfn[v]==0)
		{
			Sech(v);
			fa[v] = p;
		}
	}
}
int main(void)
{
	LL m, i, x, y, p, j, v;
	while(scanf("%lld%lld", &n, &m)!=EOF)
	{
		cnt = 0;
		for(i=1;i<=n;i++)
		{
			dfn[i] = val[i] = idom[i] = sdom[i] = 0;
			ufs[i] = key[i] = i;
			G[i].clear();
			Gp[i].clear();
			Z[i].clear();
		}
		for(i=1;i<=m;i++)
		{
			scanf("%lld%lld", &x, &y);
			G[x].push_back(y);
			Gp[y].push_back(x);
		}
		Sech(n);
		for(i=cnt;i>=2;i--)
		{
			p = rak[i];
			for(j=0;j<Gp[p].size();j++)
			{
				v = Gp[p][j];
				if(dfn[v])
				{
					Find(v);
					sdom[p] = min(sdom[p], sdom[key[v]]);
				}
			}
			ufs[p] = fa[p];
			Sp[rak[sdom[p]]].push_back(p);
			for(j=0;j<Sp[fa[p]].size();j++)
			{
				v = Sp[fa[p]][j];
				Find(v);
				if(sdom[key[v]]==sdom[v])
					idom[v] = fa[p];
				else
					idom[v] = key[v];
			}
			Sp[fa[p]].clear();
		}
		for(i=1;i<=cnt;i++)
		{
			p = rak[i];
			if(idom[p]!=rak[sdom[p]])
				idom[p] = idom[idom[p]];
		}
		for(i=1;i<=n-1;i++)
			Z[idom[i]].push_back(i);
		Sech2(n);
		printf("%lld", val[1]);
		for(i=2;i<=n;i++)
			printf(" %lld", val[i]);
		printf("\n");
	}
	return 0;
}
/*
13 21 
13 2   11 12   7 4 
2 3   12 1   6 4 
3 4   13 11 
4 5   8 12 
2 6   1 10 
6 7   10 9 
13 8   10 5 
8 9   5 13 
9 10  5 4 
8 11 
*/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值