3237: [Ahoi2013]连通图

3237: [Ahoi2013]连通图

Time Limit: 20 Sec   Memory Limit: 512 MB
Submit: 1155   Solved: 396
[ Submit][ Status][ Discuss]

Description

Input

Output

Sample Input

4 5
1 2
2 3
3 4
4 1
2 4
3
1 5
2 2 3
2 1 2

Sample Output



Connected
Disconnected
Connected

HINT


N<=100000 M<=200000 K<=100000

Source

[ Submit][ Status][ Discuss]



可以用CDQ分治解决,,不过老是wa一遍才想起为什么错。。。。。

定义Solve(l,r)为处理[l,r]的询问。

先标记[l,mid]的边,看[mid+1,r]的边,如果不在[l,mid]就插入,然后Solve(l,mid)

返回的时候先撤销上次的影响,然后标记[mid+1,r],插入[l,mid],Solve(mid+1,r)

返回的时候还是要撤销上次的影响,,这里老是忘记啊= =


维护图的连通性,支持撤销,用安轶合并的并查集

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<algorithm>
#include<cmath>
#include<stack>
using namespace std;

const int maxn = 1E5 + 10;
const int maxm = 1E5 + 10;

struct E{
	int x,y; E(){}
	E(int x,int y): x(x),y(y){}
}edgs[2*maxm];

struct data{
	int x,y,Ly; data(){}
	data(int x,int y,int Ly): x(x),y(y),Ly(Ly){}
};

int n,m,q,cnt,Mark[2*maxm],fa[maxn],L[maxn];
bool pass = 1,Ans[maxn];

vector <int> v[maxm];

int getfa(int x) {return x == fa[x]?x:getfa(fa[x]);}

void Set_Mark(int l,int r)
{
	++cnt;
	for (int i = l; i <= r; i++)
		for (int j = 0; j < v[i].size(); j++)
			Mark[v[i][j]] = cnt;
}

data Add(E e)
{
	data ret = data(0,0,0);
	int fx = getfa(e.x),fy = getfa(e.y);
	if (fx == fy) return ret;
	if (L[fx] > L[fy]) swap(fx,fy);
	ret = data(fx,fy,L[fy]);
	fa[fx] = fy; L[fy] = max(L[fy],L[fx] +1);
	return ret;
}

void Insert(int l,int r,stack <data> &s)
{
	for (int i = l; i <= r; i++)
		for (int j = 0; j < v[i].size(); j++)
		{
			if (Mark[v[i][j]] == cnt) continue;
			data ret = Add(edgs[v[i][j]]);
			if (ret.x) s.push(ret);
		}
}

void Remove(stack <data> &s)
{
	while (!s.empty())
	{
		data k = s.top(); s.pop();
		fa[k.x] = k.x; L[k.y] = k.Ly;
	}
}

void Solve(int l,int r)
{
	if (l == r)
	{
		for (int i = 0; i < v[l].size(); i++)
		{
			int fx = getfa(edgs[v[l][i]].x);
			int fy = getfa(edgs[v[l][i]].y);
			if (fx != fy) return;
		}
		Ans[l] = 1; return;
	}
	int mid = (l + r) >> 1; stack <data> s;
	Set_Mark(l,mid); Insert(mid + 1,r,s);
	Solve(l,mid); Remove(s); Set_Mark(mid + 1,r);
	Insert(l,mid,s); Solve(mid + 1,r); Remove(s);
}

int getint()
{
	char ch = getchar(); int ret = 0;
	while (ch < '0' || '9' < ch) ch = getchar();
	while ('0' <= ch && ch <= '9')
		ret = ret*10 + ch - '0',ch = getchar();
	return ret;
}

int main()
{
	#ifdef DMC
		freopen("DMC.txt","r",stdin);
	#endif
	
	n = getint(); m = getint();
	for (int i = 1; i <= n; i++) fa[i] = i;
	for (int i = 1; i <= m; i++)
	{
		int x = getint(),y = getint();
		edgs[i] = E(x,y); Add(edgs[i]);
	}
	int F = getfa(1); q = getint();
	for (int i = 2; i <= n; i++)
	{
		int k = getfa(i);
		if (k != F) {pass = 0; break;}
	}
	if (!pass)
	{
		while (q--) puts("Disconnected");
		return 0;
	}
	
	for (int i = 1; i <= q; i++)
	{
		int c = getint();
		while (c--)
		{
			int x = getint();
			v[i].push_back(x);
		}
	}
	for (int i = 1; i <= n; i++) fa[i] = i,L[i] = 0;
	Set_Mark(1,q);
	for (int i = 1; i <= m; i++)
		if (Mark[i] != cnt) Add(edgs[i]);
	Solve(1,q);
	for (int i = 1; i <= q; i++)
		if (Ans[i]) puts("Connected");
		else puts("Disconnected");
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值