zoukankan      html  css  js  c++  java
  • 题解 CF813F 【Bipartite Checking】

    题目链接

    Solution CF813F Bipartite Checking

    题目大意:给定一个有(n)个点,没有边的无向图。每次操作添加一条边,如果该边已存在则删去这条边。每次操作之后回答无向图是否为二分图

    扩展域 & 可撤销并查集、线段树分治


    分析:首先如果只有加入操作,我们可以通过扩展域并查集来判断是否可以构成二分图

    如果一个图是二分图,等价于可以对图进行黑白染色使得每条边的两端点颜色都不同

    那么我们对于一个端点(u),我们可以另开一个点(u')来表示和它颜色不同的点

    如果要加边((x,y)),就合并(x,y')(x',y)

    如果合并后任意(u)(u')在一个集合内此图都不是二分图

    原题带撤销,我们没办法快速从并查集上任意删除一条边,但是可以(O(1))撤销最后的一次修改

    因此我们可以采用线段树分治的方法

    传统的线段树维护序列,这里维护时间。由于加边删边成对出现(我们认为在时刻(q + 1)删去所有剩余边),可以利用线段树的区间修改方便的加入操作

    单点查询一个时间点,我们可以取得一系列操作,依次执行便可以得到一个时刻的答案

    如果暴力将父节点操作推给子节点,复杂度爆炸(没法(O(1)pushdown))。因此我们采用标记永久化的方式。不下传标记,用vector记录会影响一个时间段的所有操作,一路走一路累加影响,回溯的时候撤销

    对于统计一条边的出现时间段,std::map可以做到

    #include <cstdio>
    #include <cstring>
    #include <utility>
    #include <map>
    #include <stack>
    #include <vector>
    using namespace std;
    const int maxn = 1e5 + 100;
    inline int read(){
    	int x = 0;char c = getchar();
    	while(!isdigit(c))c = getchar();
    	while(isdigit(c))x = x * 10 + c - '0',c = getchar();
    	return x;
    }
    struct mpair{int fir,sec;};
    int n,q,ans[maxn];
    map<int,int> mp[maxn];
    namespace mset{
    	int f[maxn << 1],siz[maxn << 1];
    	inline void init(){
    		for(int i = 1;i <= 2 * n;i++)f[i] = i,siz[i] = 1;
    	}
    	inline int find(int x){while(f[x] != x)x = f[x];return x;}
    	inline mpair merge(int x,int y){
    		x = find(x),y = find(y);
    		if(siz[x] > siz[y])swap(x,y);
    		if(x == y)return mpair{-1,-1};
    		f[x] = y;
    		siz[y] += siz[x];
    		return mpair{x,y};
    	}
    }
    namespace seg{
    	vector<mpair> vec[maxn << 2];
    	#define ls (rt << 1)
    	#define rs (rt << 1 | 1)
    	inline void modify(int a,int b,mpair v,int l = 1,int r = q,int rt = 1){
    		if(a <= l && b >= r){
    			vec[rt].push_back(v);
    			return;
    		}
    		int mid = (l + r) >> 1;
    		if(a <= mid)modify(a,b,v,l,mid,ls);
    		if(b >= mid + 1)modify(a,b,v,mid + 1,r,rs);
    	}
    	stack<mpair> stk;
    	inline void dfs(int rt = 1,int l = 1,int r = q){
    		int t = stk.size(),flag = 1;
    		for(auto x : vec[rt]){
    			mpair res = mset::merge(x.fir,x.sec + n);
    			stk.push(res);
    			res = mset::merge(x.fir + n,x.sec);
    			stk.push(res);
    			if(mset::find(x.fir) == mset::find(x.fir + n) || mset::find(x.sec) == mset::find(x.sec + n)){
    				flag = 0;
    				break;
    			}
    		}
    		if(l == r)ans[l] = flag;
    		else if(flag){
    			int mid = (l + r) >> 1;
    			dfs(ls,l,mid);
    			dfs(rs,mid + 1,r);
    		}
    		while(stk.size() != t){
    			int x = stk.top().fir,y = stk.top().sec;
    			mset::siz[y] -= mset::siz[x];
    			mset::f[x] = x;
    			stk.pop();
    		}
    	}
    	#undef ls
    	#undef rs
    }
    int main(){
    	n = read(),q = read();mset::init();
    	for(int x,y,i = 1;i <= q;i++){
    		x = read(),y = read();
    		if(mp[x][y])seg::modify(mp[x][y],i - 1,mpair{x,y}),mp[x][y] = 0;
    		else mp[x][y] = i;
    	}
    	for(int i = 1;i <= n;i++)
    		for(auto x : mp[i])
    			if(x.second)seg::modify(x.second,q,mpair{i,x.first});
    	seg::dfs();
    	for(int i = 1;i <= q;i++)puts(ans[i] ? "YES" : "NO");
    	return 0;
    }
    
  • 相关阅读:
    LeetCode 258 Add Digits
    LeetCode 231 Power of Two
    LeetCode 28 Implement strStr()
    LeetCode 26 Remove Duplicates from Sorted Array
    LeetCode 21 Merge Two Sorted Lists
    LeetCode 20 Valid Parentheses
    图形处理函数库 ImageTTFBBox
    php一些函数
    func_get_arg(),func_get_args()和func_num_args()的用法
    人生不是故事,人生是世故,摸爬滚打才不会辜负功名尘土
  • 原文地址:https://www.cnblogs.com/colazcy/p/13393866.html
Copyright © 2011-2022 走看看