zoukankan      html  css  js  c++  java
  • LG2147 [SDOI2008]洞穴勘测(线段树分治)

    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;
    }
    
    
  • 相关阅读:
    检测登录按钮 ,回车即登录
    [转]程序变量命名推荐规范
    [NET].NET Framework 3.5 SP1 真正的离线安装(转)
    Arthas使用教程[转载]
    Python中Hamcrest断言的使用
    C#中查询不支持中文的解决方法
    如何防止C#的小黑窗关闭
    AWS的EC2 micro instance真是慢啊
    一键分享文字图片到新浪微博,facebook,twitter 还有保存打印等 (使用 iOS6 自带的 social.framework)
    自己写的可以布置多个button在同一行的ActionSheet (iPhone)
  • 原文地址:https://www.cnblogs.com/huayucaiji/p/LG2147.html
Copyright © 2011-2022 走看看