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

LG2147 [SDOI2008]洞穴勘测

时间:2021-03-08 13:37:41      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:return   mod   撤销   can   getchar   you   oid   lang   ret   

LG2147 [SDOI2008]洞穴勘测

这个题第一眼是线段树分治吧。

但是这个题和大部分板子不同的是,这里询问不是全图连通性了,是两点的连通性。其实思路没什么大区别,还是要用可撤销并查集维护连通性,把边挂到线段树上相应的时间点上。

只是我们现在的询问不同了,我们可以模仿把边挂在线段树上的方式,把询问挂在单点上。每个时间点上最多有一次询问,由于线段树上的点是按时间顺序排列的,我们在遍历到这个点的时候,直接输出结果即可。


//Don‘t act like a loser.
//This code is written by huayucaiji
//You can only use the code for studying or finding mistakes
//Or,you‘ll be punished by Sakyamuni!!!
#include<bits/stdc++.h>
#define int long long
#define pr pair<int,int>
using namespace std;

int read() {
	char ch=getchar();
	int f=1,x=0;
	while(ch<‘0‘||ch>‘9‘) {
		if(ch==‘-‘)
			f=-1;
		ch=getchar();
	}
	while(ch>=‘0‘&&ch<=‘9‘) {
		x=x*10+ch-‘0‘;
		ch=getchar();
	}
	return f*x;
}

const int MAXN=10000+10,MAXM=2e5+10;

int n,m,q,cnt,num;
stack<pr > stk;
int size[MAXN],father[MAXN];
vector<pr > edge[MAXM<<2];
vector<pr > qry[MAXM<<2];
set<pr > s;
map<pr,int > mp;

pr make_edge(int x,int y) {
	return make_pair(min(x,y),max(x,y));
}
int find(int x) {
	if(x!=father[x]) {
		return find(father[x]);
	}
	return x;
}
void merge(pr s) {
	int x=find(s.first);
	int y=find(s.second);
	if(x==y) {
		stk.push(make_pair(-1,-1));
		return ;
	}
	if(size[x]>size[y]) {
		swap(x,y);
	}
	father[x]=y;
	size[y]+=size[x];
	stk.push(make_pair(x,y));
}
void del() {
	int x=stk.top().first;
	int y=stk.top().second;
	stk.pop();
	if(x==-1) {
		return ;
	}
	father[x]=x;
	size[y]-=size[x];
}

void modify(int l,int r,int p,int x,int y,pr s) {
	if(x>y||r<x||y<l) {
		return ;
	}
	if(x<=l&&r<=y) {
		edge[p].push_back(s);
		return ;
	}
	
	int mid=(l+r)>>1;
	modify(l,mid,p<<1,x,y,s);
	modify(mid+1,r,p<<1|1,x,y,s);
}
void modqry(int l,int r,int p,int x,int y,pr s) {
	if(x>y||r<x||y<l) {
		return ;
	}
	if(x<=l&&r<=y) {
		qry[p].push_back(s);
        //把询问挂到线段树上
		return ;
	}
	
	int mid=(l+r)>>1;
	modqry(l,mid,p<<1,x,y,s);
	modqry(mid+1,r,p<<1|1,x,y,s);
}

void query(int l,int r,int p) {
	int sz=edge[p].size();
	for(int i=0;i<sz;i++) {
		merge(edge[p][i]);
	}
	if(l==r) {
		int qsz=qry[p].size();
        //qsz的值域在 [0,1]。
		for(int i=0;i<qsz;i++) {
			if(find(qry[p][i].first)==find(qry[p][i].second)) {
				puts("Yes");
			}
			else {
				puts("No");
			}
		}
	}
	else {
		int mid=(l+r)>>1;
		query(l,mid,p<<1);
		query(mid+1,r,p<<1|1);
	} 
	while(sz--) {
		del();
	}
}

signed main() {
	cin>>n;
	for(int i=1;i<=n;i++) {
		father[i]=i;
		size[i]=1;
	}
	cin>>q;
	
	for(int i=1;i<=q;i++) {
		string c;
		cin>>c;
		int u,v;
		u=read();
		v=read();
		if(c[0]==‘Q‘) {
			modqry(1,q,1,i,i,make_pair(u,v));
		}
		if(c[0]==‘C‘) {
			s.insert(make_edge(u,v));
			mp[make_edge(u,v)]=i;
		}
		if(c[0]==‘D‘) {
			modify(1,q,1,mp[make_edge(u,v)],i-1,make_edge(u,v));
			mp[make_edge(u,v)]=0;
			s.erase(make_edge(u,v));
		}
	}
	
	for(set<pr >::iterator it=s.begin();it!=s.end();it++) {
		modify(1,q,1,mp[*it],q,*it);
        //还有些边没被删除要加进去
	}
	
	query(1,q,1);
	return 0;
}

LG2147 [SDOI2008]洞穴勘测

标签:return   mod   撤销   can   getchar   you   oid   lang   ret   

原文地址:https://www.cnblogs.com/huayucaiji/p/LG2147.html

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