• A-Graph Games_2019牛客暑期多校训练营(第三场)


    题意

    给出一张无向图,定义S[x]表示与点x直接相连的点集,有两个操作
    1 x y表示将第x到第y条边状态变化(若存在则删除,不存在则建立)
    2 x y询问S[x]与S[y]是否相等

    题解

    有一个技巧可以压缩的表示点集:给每个点随机一个key,S[x]就可以表示为
    与x相连的点的key亦或起来。
    考虑如何维护S[x], 因为修改操作是对输入的顺序的区间修改,我们就按边输入的
    顺序进行分块,用sum[i][j]记录第i块对点j的贡献值,也就是如果第i块有一条边u-v
    那么(sum[i][u] igoplus= key[v], sum[i][v] igoplus= key[u])
    查询一个点的点集就变成求(sum[1][x] igoplus sum[2][x] igoplus sum[3][x] cdots igoplus sum[num][x])
    修改的时候如果修改区间落在不同的块上,对夹在中间的块打个lazy标记,表示查询的时候
    不用亦或上这个块的贡献,对与两边块内的修改操作可以再用一个数组S记录暴力修改的状态,
    比如要修改区间([l,r])是块内的,那么就修改(S[u[i]] igoplus= key[v[i]], S[v[i]] igoplus= key[u[i]] (iin[l,r]))
    查询x的点集时再xor上S[x]就行,总的来说就是块间修改只需要对sum打标记,块内修改就
    暴力更改S,最后复杂度(O(qsqrt m)),分块的时候块数要开成(1.5sqrt m)

    代码

    #include <bits/stdc++.h>
    
    using namespace std;
    const int mx = 2e5+10;
    typedef long long ll;
    
    int belong[mx], block, num, l[mx], r[mx], id[mx];
    int n, m, q, u[mx], v[mx];
    int lazy[mx];
    ll  sum[450][mx], S[mx];
    
    void build() {
        block = 1.5*sqrt(m);
        num = m / block;
        if (m % block) num++;
        for (int i = 1; i <= num; i++) {
            l[i] = (i-1) * block + 1;
            r[i] = i * block;
            lazy[i] = 1;
            for (int j = 1; j <= n; j++)
                sum[i][j] = 0;
        }
        r[num] = m;
        for (int i = 1; i <= m; i++)
            belong[i] = (i-1) / block + 1;
        for (int i = 1; i <= n; i++) S[i] = 0;
             
    }
    
    void update(int x, int y) {
        if (belong[x] == belong[y]) {
            for (int i = x; i <= y; i++) {
                S[u[i]] ^= id[v[i]];
                S[v[i]] ^= id[u[i]];
            }
            return;
        }
        int L = belong[x], R = belong[y];
        for (register int i = x; i <= r[L]; i++) {
            S[u[i]] ^= id[v[i]];
            S[v[i]] ^= id[u[i]];
        }
        for (register int i = L+1; i < R; i++) lazy[i] ^= 1;
        for (register int i = l[R]; i <= y; i++) {
            S[u[i]] ^= id[v[i]];
            S[v[i]] ^= id[u[i]];
        }
    }
    
    
    int main() {
        srand(time(NULL));
        for (int i = 1; i < 100005; i++) id[i] = rand() + 1;
        int T;
        scanf("%d", &T);
    
        while (T--) {
            scanf("%d%d", &n, &m);
            build();
            for (int i = 1; i <= m; i++) {
                scanf("%d%d", &u[i], &v[i]);
                sum[belong[i]][u[i]] ^= id[v[i]];
                sum[belong[i]][v[i]] ^= id[u[i]];
            }
            scanf("%d", &q);
            while (q--) {
                int op, x, y;
                scanf("%d%d%d", &op, &x, &y);
                if (op == 1) {
                    update(x, y);
                } else {
                    ll ansx = S[x], ansy = S[y];
                    for (int i = 1; i <= num; i++) {
                        if (lazy[i]) {
                            ansx ^= sum[i][x];
                            ansy ^= sum[i][y];
                        }
                    }
                    putchar(ansx==ansy?'1':'0');
                }
            }
            putchar('
    ');
        }
        return 0;
    }
    
  • 相关阅读:
    三行Python代码查询IP
    剑指offer面试题29:数组中出现次数超过一半的数字
    【简】题解 AWSL090429 【数塔问题】
    Re.常系数齐次递推
    Re.多项式除法/取模
    【翻译】A simple stone game
    Re.多项式求逆
    Re.FFT
    题解 P4783 【【模板】矩阵求逆】
    关于win10企业版在极域电子教室软件 v4.0 2015 豪华版的全屏控制下如何取得自由
  • 原文地址:https://www.cnblogs.com/bpdwn-cnblogs/p/11290523.html
Copyright © 2020-2023  润新知