zoukankan      html  css  js  c++  java
  • 5.10 省选模拟赛 网格 平面图欧拉定理 并查集

    LINK:网格

    avatar
    avatar

    搞了一下午 总算把这个平面欧拉定理给搞懂了。

    大体上是欧拉定理 的一些定义难以理解。

    关于证明我也不太会。题解写的那叫一个抽象 最终看std明白了题解的意思。

    平面图欧拉定理:定义 V是点数 E为边数 F为区域数 C为连通块个数

    那么存在 V+F-E=C+1;的关系。

    其中 关于边数E的则认为是一个八联通的边 对于区域则需要百度一下 当然三角形也算是一个区域 (广大的UOJ群友就是牛.

    对于前者 在定理中就是定义 在这道题中则容易想到边的关系显然包含斜着的边 后者同理。

    考虑这道题的暴力 第一子任务是暴力bfs 不过遇到边界就加上一些特殊操作。

    对于第二个子任务 这个我没实现 想到一个复杂度为n^3的东西 每次便利整张图 然后利用 dfs树的性质来判断区域。不过实现较麻烦 可能还通过不了。

    对于第三个子任务 离线之后容易想到利用并查集判断联通性 每次加边判断连通块的增减性即可。

    对于第四个子任务 用第三个就不太能写了 关键是整张图的连通块个数不能得到 且后续操作也完成不了。

    code: score 35

    const int MAXN = 100010, maxn = 210, N = 1001010, MAX = 1010;
    ;
    const int dx[4] = { 0, 0, 1, -1 };
    const int dy[4] = { 1, -1, 0, 0 };
    int T, Q, flag1, ans, id, flag, flag2, root;
    struct wy {
        int x, y;
    } t[MAXN];
    int b[maxn][maxn], vis[MAX][MAX];
    int f[N], mark[N], ans1[MAXN];
    queue<pii> q;
    inline void bfs(int s1, int s2) {
        q.push(mk(s1, s2));
        while (q.size()) {
            int x = q.front().F;
            int y = q.front().S;
            q.pop();
            for (int i = 0; i < 4; ++i) {
                int xx = dx[i] + x;
                int yy = dy[i] + y;
                if (xx < 0 || yy<0 | xx> 200 || yy > 200) {
                    flag = 1;
                    continue;
                }
                if (vis[xx][yy])
                    continue;
                if (b[xx][yy] == id)
                    continue;
                b[xx][yy] = id;
                q.push(mk(xx, yy));
            }
        }
    }
    inline void sol1() {
        rep(1, Q, i) {
            int x = t[i].x ^ (T * ans);
            int y = t[i].y ^ (T * ans);
            x += 100;
            y += 100;
            vis[x][y] = 1;
            int cnt = 1;
            ++id;
            rep(0, 200, i) {
                rep(0, 200, j) {
                    if (vis[i][j])
                        continue;
                    if (b[i][j] == id)
                        continue;
                    flag = 0;
                    b[i][j] = id;
                    bfs(i, j);
                    if (!flag)
                        ++cnt;
                }
            }
            ans = cnt;
            put(ans);
        }
        exit(0);
    }
    inline int getfather(int x) { return x == f[x] ? x : f[x] = getfather(f[x]); }
    inline void merge(int x, int y) {
        int xx = getfather(x);
        int yy = getfather(y);
        f[xx] = yy;
        return;
    }
    inline void sol2() {
        root = 1001001;
        f[root] = root;
        rep(1, Q, i) {
            t[i].x += 500;
            t[i].y += 500;
            int x = t[i].x;
            int y = t[i].y;
            vis[x][y] = 1;
        }
        rep(0, 1000, i) rep(0, 1000, j) f[i * 1000 + j] = i * 1000 + j;
        rep(0, 1000, i) rep(0, 1000, j) {
            if (vis[i][j])
                continue;
            int id1 = i * 1000 + j;
            rep(0, 3, k) {
                int xx = dx[k] + i;
                int yy = dy[k] + j;
                if (xx < 0 || yy < 0 || xx > 1000 || yy > 1000)
                    merge(root, id1);
                else {
                    if (vis[xx][yy])
                        continue;
                    merge(xx * 1000 + yy, id1);
                }
            }
        }
        rep(0, 1000, i) rep(0, 1000, j) {
            if (vis[i][j])
                continue;
            int xx = getfather(i * 1000 + j);
            if (!mark[xx])
                ++ans;
            mark[xx] = 1;
        }
        fep(Q, 1, i) {
            ans1[i] = ans;
            int x = t[i].x;
            int y = t[i].y;
            int id1 = x * 1000 + y;
            f[id1] = id1;
            vis[x][y] = 0;
            ++ans;
            rep(0, 3, k) {
                int xx = dx[k] + x;
                int yy = dy[k] + y;
                if (xx < 0 || yy < 0 || xx > 1000 || yy > 1000) {
                    if (getfather(id1) != getfather(root))
                        --ans;
                    merge(id1, root);
                } else {
                    if (vis[xx][yy])
                        continue;
                    if (getfather(id1) != getfather(xx * 1000 + yy))
                        --ans;
                    // cout<<getfather(xx*1000+yy)<<' '<<getfather(id1)<<endl;
                    merge(id1, xx * 1000 + yy);
                }
            }
            // put(ans);
        }
        rep(1, Q, i) put(ans1[i]);
        exit(0);
    }
    int main() {
        // freopen("1.in","r",stdin);
        // freopen("1.out","w",stdout);
        get(Q);
        get(T);
        rep(1, Q, i) {
            int get(x), get(y);
            t[i] = (wy){ x, y };
            if (abs(x) > 100 && abs(y) > 100)
                flag1 = 1;
            if (abs(x) > 500 && abs(y) > 500)
                flag2 = 1;
        }
        if (!flag1)
            sol1();
        if (!flag2 && !T)
            sol2();
        return 0;
    }
    

    正解就是利用欧拉定理来做。

    容易想到最后答案求得其实是F-实心区域个数。

    而容易发现实心的区域个数一定是为三角形的区域。

    所以 我们仍要多维护一个三角形区域个数 设为O.

    V直接维护 E也直接维护 C利用并查集维护 关键是对于O的维护 加入一个点的时候 这个点会造成贡献无疑是和其8联通的正方形。

    暴力枚举12个三角形就可以维护。

    更简便的方法是 枚举每个三角形的右下角 然后再枚举右上方极小正方形来判断。

    值得注意的是 可能加上之前的三角形区域了 先减掉之前的即可。

    const int MAXN = 100010;
    const int dx[8] = { -1, -1, -1, 0, 0, 1, 1, 1 };
    const int dy[8] = { 0, -1, 1, 1, -1, -1, 0, 1 };
    int Q, T;
    int ans, f[MAXN];
    int V, E, C, O;
    map<ll, int> H;
    inline int getfather(int x) { return x == f[x] ? x : f[x] = getfather(f[x]); }
    inline ll ha(int x, int y) {
        x += INF, y += INF;
        return (ll)x << 31 | y;
    }
    inline int qy(int x, int y) {
        int cnt = 0;
        if (H.find(ha(x, y)) != H.end())
            ++cnt;
        if (H.find(ha(x + 1, y)) != H.end())
            ++cnt;
        if (H.find(ha(x, y + 1)) != H.end())
            ++cnt;
        if (H.find(ha(x + 1, y + 1)) != H.end())
            ++cnt;
        if (cnt == 3)
            return 1;
        if (cnt == 4)
            return 3;
        return 0;
    }
    int main() {
        // freopen("1.in","r",stdin);
        get(Q);
        get(T);
        rep(1, Q, i) {
            int get(x) ^ (T * ans), get(y) ^ (T * ans);
            ll ww = ha(x, y);
            ++V;
            ++C;
            O -= qy(x, y);
            O -= qy(x - 1, y);
            O -= qy(x, y - 1);
            O -= qy(x - 1, y - 1);
            H[ww] = i;
            f[i] = i;
            O += qy(x, y);
            O += qy(x - 1, y);
            O += qy(x, y - 1);
            O += qy(x - 1, y - 1);
            for (int j = 0; j < 8; ++j) {
                int xx = dx[j] + x;
                int yy = dy[j] + y;
                if (H.find(ha(xx, yy)) == H.end())
                    continue;
                int ww = H[ha(xx, yy)];
                int w1 = getfather(i);
                int w2 = getfather(ww);
                ++E;
                if (w1 != w2) {
                    f[w1] = w2;
                    --C;
                }
            }
            put(ans = (E + C + 1 - V - O));
            // cout<<E<<' '<<V<<' '<<C<<' '<<O<<'
    ';
        }
        return 0;
    }
    
  • 相关阅读:
    python_之无参装饰器_01
    一 :接口自动化之 Rquests封装
    python --字典基本用法
    hadoop集群通过web管理界面只显示一个节点
    Hadoop基础(十八):MapReduce框架原理(二)切片机制(二)
    Hadoop基础(十七):MapReduce框架原理(一)切片机制(一)
    Hadoop基础(十六):Hadoop序列化
    Hadoop基础(十五): MapReduce概述
    Hadoop基础(十四): HDFS 2.X新特性
    Hadoop基础(十三): DataNode
  • 原文地址:https://www.cnblogs.com/chdy/p/12871067.html
Copyright © 2011-2022 走看看