码迷,mamicode.com
首页 > 其他好文 > 详细

bzoj3082: Graph2 离线+线段树

时间:2016-08-27 21:55:50      阅读:155      评论:0      收藏:0      [点我收藏+]

标签:

经典问题。强制在线的话非常复杂。

考虑离线。

每条边的存在时间是一个区间,因此按时间建立一颗线段树,将每条边插入,拆成log条边。然后dfs线段树,每次并查集合并当前节点的所有边,到叶子节点时回答询问,回溯时撤销并查集的修改。

带撤销的并查集不能路径压缩,要按秩合并。

#include<bits/stdc++.h>
#define N 200005
#define M (l+r>>1)
#define P (k<<1)
#define S (k<<1|1)
#define L l,M,P
#define R M+1,r,S
#define Z int l=1,int r=q,int k=1
#define u first
#define v second
using namespace std;
struct io_t{
	operator int(){
		int x;
		scanf("%d",&x);
		return x;
	}
}it;
int n=it,m=it,s[N],t[N];
int p[N],u[N],v[N],j,q;
char d[N];
typedef pair<int,int> vec;
vec f[N],e[N];
vector<vec> a[1<<18];
int find(int i){
	return p[i]==i
	?i:find(p[i]);
}
void add(vec v,int s,int t,Z){
	if(s<=l&&r<=t)
		a[k].push_back(v);
	else{
		if(s<=M)
			add(v,s,t,L);
		if(t>M)
			add(v,s,t,R);
	}
}
void dfs(Z){
	for(int j=0;j!=a[k].size();++j){
		vec* i=&a[k][j];
		i->u=find(i->u);
		i->v=find(i->v);
		if(i->u^i->v){
			if(u[i->u]<u[i->v])
				swap(i->u,i->v);
			p[i->v]=i->u;
			u[i->u]+=u[i->v];
		}
	}
	if(l==r)
		d[l]^81?0:v[l]
		=find(f[l].u)
		^find(f[l].v);
	else{
		dfs(L);dfs(R);
	}
	for(int j=a[k].size()-1;~j;--j){
		vec* i=&a[k][j];
		if(i->u^i->v){
			p[i->v]=i->v;
			u[i->u]-=u[i->v];
		}
	}
}
int main(){
	for(int i=1;i<=n;++i)
		u[p[i]=i]=1;
	for(int i=1;i<=m;++i)
		e[i]=vec(it,it);
	q=it;
	for(int i=1;i<=q;++i){
		scanf(" %c%d",d+i,&j);
		if(d[i]==68)
			t[j]?0:t[j]=i;
		if(d[i]==81)
			f[i]=vec(j,it);
		if(d[i]==73&&++m){
			s[m]=i;
			e[m]=vec(j,it);
		}
	}
	for(int i=1;i<=m;++i)
		add(e[i],
		s[i],t[i]?t[i]:q);
	dfs();
	for(int i=1;i<=q;++i)
		if(d[i]==81)
			puts(v[i]?"No":"Yes");
}

  

bzoj3082: Graph2 离线+线段树

标签:

原文地址:http://www.cnblogs.com/f321dd/p/5813830.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!