UOJ#14【UER#1】DZY Loves Graph

题目链接:http://uoj.ac/problem/14


【分析】

    先请允许我诚意地orz DZY神犇...

    UOJ的题解真的很良心...http://vfleaking.blog.uoj.ac/blog/15

    主要内容就是一个按秩合并的并查集,支持删边加边。在没有Return操作的情况下,这么做是nlogn的,已经足够了,但是有Return操作,在删完大量的边后重新加边会使时间复杂度变成n^2。

    这时考虑离线处理,在进行Delete操作之前看看下一个操作是不是Return,如果不是就删边,如果是就不要删边,事先用一个数组Res[i]记录一下图中边数为i时最小生成树的大小,本次Delete操作的结果就是Res[当前图中边数-删去的边数]。


【代码】

#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long LL;
const int maxn=500010;

char cor[maxn][10];
int corx[maxn],cory[maxn];
int size[maxn],f[maxn],Ef[maxn];
int Q[maxn],tail;
LL Res[maxn];
int n,m;

void Init()
{
	scanf("%d%d",&n,&m);
	int x,y;
	for (int i=1;i<=m;i++)
	{
		scanf("%s",cor[i]);
		if (cor[i][0]=='A') scanf("%d%d",&corx[i],&cory[i]);
		else if (cor[i][0]=='D') scanf("%d",&corx[i]);
	}
}

int Find(int x) {return (f[x]==x)?x:Find(f[x]);}

void Add_Edge(int x,int y,int d)
{
	int px=Find(x),py=Find(y);
	Q[tail++]=d;
	if (px==py) {Ef[d]=-1;return;}
	if (size[px]>size[py]) swap(px,py);
	f[px]=py;
	for (int i=py;;py=f[py])
	{
		size[py]+=size[px];
		if (f[py]==py) break;
	}
	Ef[d]=px;
}

void Delete(int p)
{
	for (int px=f[p];;px=f[px])
	{
		size[px]-=size[p];
		if (f[px]==px) break;
	}
	f[p]=p;
}

void Solve()
{
	int tot=0,trcnt=0;
	LL ans=0;
	for (int i=1;i<=n;i++) f[i]=i,size[i]=1;
	for (int i=1;i<=m;i++)
	if (cor[i][0]=='A')
	{
		Add_Edge(corx[i],cory[i],i);
		if (Ef[i]!=-1) ans+=i,trcnt++;
		Res[++tot]=(trcnt<n-1)?0:ans;
		printf("%lld\n",Res[tot]);
		if (cor[i+1][0]=='R') cor[i+1][0]='D',corx[i+1]=1;
	}
	else if (cor[i][0]=='D')
	{
		if (cor[i+1][0]=='R') {printf("%lld\n%lld\n",Res[tot-corx[i]],Res[tot]);continue;}
		while (corx[i]--)
		{
			int p=Q[--tail];tot--;
			if (Ef[p]==-1) continue;
			Delete(Ef[p]);
			ans-=p;trcnt--;
		}
		Res[tot]=(trcnt<n-1)?0:ans;
		printf("%lld\n",Res[tot]);
	}
}

int main()
{
	Init();
	Solve();
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值