zoukankan      html  css  js  c++  java
  • 2019牛客多校第三场A Graph Games 分块思想

    题意:给你一张无向图,设s(x)为与x直接相连的点的集合,题目中有两种操作:

    1:1 l r 将读入的边的序列中第l个到第r个翻转状态(有这条边 -> 没这条边, 没这条边 -> 有这条边)

    2:2 x y 询问s(x)和s(y)是否相等。

    思路(官方题解):首要问题是怎么快速判断s(x)和s(y)是否相等。我们发现边的翻转操作实际上是异或操作,所以不妨给每个点随机一个值,用与x直接相连的点的异或和作为s(x),这样可以快速判断s(x)和s(y)是否相等。判相等解决了,怎么快速维护操作1呢?我们发现好像不好直接维护,因为把一个区间的边翻转了,好像除了遍历,很难知道具体影响了哪些点,或者我们只标记翻转,计算s(x)的时候枚举和x相连的边,判断是否翻转。这两种好像复杂度都比较高,但是我们可以折中一下,我们对点进行分类,根据度数是否大于sqrt(m),分为小点和大点两类。这个套路之前见过,放上链接https://www.cnblogs.com/pkgunboat/p/10995209.html对于小点,边数不超过sqrt(m),直接暴力判断是否翻转就可以了。对于大点,由于大点只有O(sqrt(m))种,相对比较好维护。我们可以对边序列分块,维护每一个块如果整体翻转了对某个大点的贡献。这样,我们在进行区间操作的时候,在块间打翻转标记,在两侧暴力翻转,如果翻转的边的端点是大点,就直接把影响加上。询问的时候,看一下所有块的整体翻转情况,如果整体是翻转的,因为之前已经预处理了所有块对大点的翻转影响,所以把影响加上。这样每次询问复杂度O(sqrt(m))。

    代码:

    #include <bits/stdc++.h>
    #define LL long long
    #define pii pair<int, int>
    using namespace std;
    const int maxn = 200010;
    LL val[maxn], now[maxn];
    LL f[510][1010];
    bool flip[510], v[maxn];
    bool is_big[maxn];
    vector<pii> G[maxn];
    int pos[maxn], L[maxn], R[maxn], mp[maxn], tot;
    random_device rd;
    mt19937 Random(rd());
    //LL Random() {
    //	return (LL)rand() * rand();
    //}
    struct edge{
    	int u, v;
    };
    edge e[maxn];
    LL get(LL mod) {
    	return ((__int128)Random() * Random()) % mod;
    }
    void change(int l, int r) {
    	int p = pos[l], q = pos[r];
    	if(p == q) {
    		for (int i = l; i <= r; i++) {
    			v[i] ^= 1;
    			if(is_big[e[i].u]) now[e[i].u] ^= val[e[i].v];
    			if(is_big[e[i].v]) now[e[i].v] ^= val[e[i].u];
    		}
    	} else {
    		for (int i = p + 1; i <= q - 1; i++) {
    			flip[i] ^= 1;
    		}
    		for (int i = L[q]; i <= r; i++) {
    			v[i] ^= 1;
    			if(is_big[e[i].u]) now[e[i].u] ^= val[e[i].v];
    			if(is_big[e[i].v]) now[e[i].v] ^= val[e[i].u];
    		}
    		for (int i = l; i <= R[p]; i++) {
    			v[i] ^= 1;
    			if(is_big[e[i].u]) now[e[i].u] ^= val[e[i].v];
    			if(is_big[e[i].v]) now[e[i].v] ^= val[e[i].u];
    		}
    	}
    }
    int main() {
    	int T, op, x, y, n, m, T1;
    	srand(time(0));
    	scanf("%d", &T);
    	while(T--) {
    		tot = 0;
    		scanf("%d%d", &n, &m);
    		for (int i = 1; i <= n; i++) {
    			val[i] = get(1e18);
    			G[i].clear();
    			now[i] = 0;
    			flip[i] = 0;
    		}
    		for (int i = 1; i <= m; i++) {
    			scanf("%d%d", &e[i].u, &e[i].v);
    			G[e[i].u].push_back(make_pair(e[i].v, i));
    			G[e[i].v].push_back(make_pair(e[i].u, i));
    			now[e[i].v] ^= val[e[i].u];
    			now[e[i].u] ^= val[e[i].v];
    		}
    		int t = sqrt(m);
    		int block = t;
    		for (int i = 1; i <= t; i++) {
    			L[i] = (i - 1) * block + 1;
    			R[i] = i * block;
    		}
    		if(R[t] < m) {
    			t++;
    			L[t] = R[t - 1] + 1;
    			R[t] = m;
    		}
    		for (int i = 1; i <= n; i++) {
    			if(G[i].size() >= block) {
    				is_big[i] = 1;
    				mp[i] = ++tot;
    			} else {
    				is_big[i] = 0;
    				mp[i] = 0;
    			}
    		}
    		assert(tot <= 1000);
    		assert(t <= 500);
    		for (int i = 1; i <= t; i++) {
    			for (int j = 1; j <= tot; j++)
    				f[i][j] = 0;
    			for (int j = L[i]; j <= R[i]; j++) {
    				pos[j] = i;
    				v[j] = 0;
    			}
    		}
    		for (int i = 1; i <= t; i++) {
    			for (int j = L[i]; j <= R[i]; j++) {
    				if(is_big[e[j].u]) {
    					f[i][mp[e[j].u]] ^= val[e[j].v];
    				}
    				if(is_big[e[j].v]) {
    					f[i][mp[e[j].v]] ^= val[e[j].u];
    				}
    			}
    		}
    		scanf("%d", &T1);
    		while(T1--) {
    			scanf("%d%d%d", &op, &x, &y);
    			if(op == 1) {
    				change(x, y);
    			} else {
    				LL ans1 = now[x], ans2 = now[y];
    				if(is_big[x]) {
    					for (int i = 1; i <= t; i++) {
    						if(flip[i]) ans1 ^= f[i][mp[x]];
    					}
    				} else {
    					for (int i = 0; i < G[x].size(); i++) {
    						pii tmp = G[x][i];
    						if(v[tmp.second] ^ flip[pos[tmp.second]])
    							ans1 ^= val[tmp.first];
    					}
    				}
    				if(is_big[y]) {
    					for (int i = 1; i <= t; i++) {
    						if(flip[i]) ans2 ^= f[i][mp[y]];
    					}
    				} else {
    					for (int i = 0; i < G[y].size(); i++) {
    						pii tmp = G[y][i];
    						if(v[tmp.second] ^ flip[pos[tmp.second]])
    							ans2 ^= val[tmp.first];
    					}
    				}
    				if(ans1 == ans2) {
    					printf("1");
    				} else {
    					printf("0");
    				}
    			}
    		}
    		printf("
    ");
    	}
    }
    

      

  • 相关阅读:
    使用Power Query从Web页面获取图像到Power BI报告中
    视频 |【2019】Power BI 8月产品功能更新讲解
    【2019】微软Power BI 每月功能更新系列——Power BI 8月版本功能完整解读
    视频 |【2019】Power BI 7月产品功能更新讲解
    2019 年 BI 平台 Top 14
    2016 黑客必备的Android应用都有哪些?
    J2EE完全手册(二)
    JavaBean ,Enterprise Bean(EJB), 三种Bean, 以及POJO
    J2EE完全手册(一)
    J2EE简介
  • 原文地址:https://www.cnblogs.com/pkgunboat/p/11253569.html
Copyright © 2011-2022 走看看