• hdu 6756 Finding a MEX 线段树


    2020 Multi-University Training Contest 1

    hdu 6756 Finding a MEX 线段树

    题意:

    给你一张图, 每个点有个权值, 你有q次操作 第一种询问 u节点连的点 的权值第一次没用出现的数最小

    第二中操作, 修改 u的权值为x

    题解:

    这题实在是有点恶心, 朝鲜老哥太会卡了, 我优化了好久才没用t.

    先说下思路:

    我们将点 分为 大点,与小点,所谓的大点就是 该点连的边的个数 $ge sqrt(n) $ 小点就是 (< sqrt(n))

    为啥要这样分?

    这样分的好处就是 让修改的操作的复杂度变为 sqrt(n) * log(n),

    查询的复杂度最坏也是 sqrt(n)

    也就是 大于 sqrt(n)的建一颗线段树, 小于的就直接暴力, 这样相互利用优点让总时间复杂度 为

    q * sqrt(n) * log(n)

    如果你直接这样写, 不把能优化的都优化, 那么肯定t

    优化部分:

    • 有重边, 所以建图要去重
    • 权值线段不要开 1e9, 因为没用必要, 只要权值开到每个节点连的边个个数就行了, 因为你要求的是mex 如果 这些数 有大于 节点的边数, 那么答案一定再节点边数的范围类, 如果 点的边数这个范围都要值, 那么答案一定是0 。

    代码:

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N = 4e5 + 7;
    
    struct segement {
        int sum, l, r;
        int count;
    }tree[60 * N];
    
    vector<int> G[N];
    vector<int> mp[N];
    
    
    
    
    
    int n, mm, q, top = 1, rt[N], a[N];
    
    
    #define m (l + r) / 2
    
    
    
    
    void up(int v, int pos, int l, int r, int &node) {
        if (pos > r) return;
        if (!node) node = top++;
        if (l == r) {
            tree[node].count += v;
            if (tree[node].count > 0) {
                tree[node].sum = 1;
            } else {
                tree[node].sum = 0;
            }
            return;
        }
        if (pos <= m) up(v, pos, l, m, tree[node].l);
        else  up(v, pos, m + 1, r, tree[node].r);
        tree[node].sum = tree[tree[node].l].sum + tree[tree[node].r].sum;
    
    
    }
    
    int query(int l, int r, int node) {
        if (l == r) return l;
        if ((m - l + 1) > tree[tree[node].l].sum) {
            return query(l, m, tree[node].l);
        } else {
            return query(m + 1, r, tree[node].r);
        }
    
    }
    
    int du[N];
    
    vector<int>num[N];
    
    
    int main() {
     
    
        int t; scanf("%d", &t);
        while (t--) {
            scanf("%d %d", &n, &mm);
            for (int i = 1; i <= n; i++) {
                scanf("%d", &a[i]);
            }
            top = 1;
            for (int i = 1; i <= n; i++) {
                G[i].clear();
                mp[i].clear();
                du[i] = 0;
                rt[i] = 0;
                num[i].clear();
            }
            for (int i = 1; i <= mm; i++) {
                int u, v;
                scanf("%d %d", &u, &v);
                G[u].push_back(v);
                G[v].push_back(u);
            }
             int block = (int)sqrt(n);
    
            for (int i = 1; i <= n; i++) {
                 sort(G[i].begin(), G[i].end());
                 G[i].erase(unique(G[i].begin(), G[i].end()), G[i].end());
                    du[i] = G[i].size();
            }
    
            for (int i = 1; i <= n; i++) {
                for (int to: G[i]) {
                    if (du[to] >= block) {
                        mp[i].push_back(to);
                    }
                }
            }
            for (int i = 1; i <= n; i++) {
                if (du[i] >= block) {
                    num[i].resize(du[i] + 2);
                    for (int to: G[i]) {
                        if (a[to] <= du[i]) {
                            if (++num[i][a[to]] == 1)
                                up(1, a[to], 0, du[i], rt[i]);
                        }
                       
                        
                    }
                }
            }
    
            int q; scanf("%d", &q);
            while (q--) {
                int op; scanf("%d", &op);
                if (op == 1) {
                    int u, x; scanf("%d %d", &u, &x);
                    if (a[u] == x) continue;
                    for (int to: mp[u]) {
                        if (a[to] <= du[to]) {
                            if ((--num[to][a[u]]) == 0)
                                up(-1, a[u], 0, du[to], rt[to]);
                        }
                        if (x <= du[to]) {
                            if (++num[to][x] == 1)
                                up(1, x, 0, du[to], rt[to]);
                        }
                        
                    }
                    a[u] = x;
                } else {
                    int u; scanf("%d", &u);
                    if (du[u] >= block) {
                        int ans = query(0, du[u], rt[u]);
                        printf("%d
    ", ans);
                    } else {
                        vector<int> v;
                        v.resize(400);
                        for (int to: G[u]) {
                            if (a[to] >= 400) continue;
                            v[a[to]]++;
                        }
            
                        int ans = 0;
                        for (int i = 0; i < 400; i++) {
                            if (v[i] == 0) {
                                ans = i;
                                break;
                            }
                        }
                        printf("%d
    ", ans);
                    }
                }
            }
            for (int i = 0; i <= top; i++) {
                tree[i].count = tree[i].l = tree[i].r = tree[i].sum = 0;
            }
    
           
        }
    }
    
  • 相关阅读:
    shell脚本使用记录一:操作文件
    用IDEA在Tomcat上部署项目
    通过反射获取属性名和属性类型
    IDEA设置生成类基本注释信息
    有序的Map集合--LinkedHashMap
    书面格式注意的问题
    悲观锁和乐观锁的区别
    解析xml文件的四种方式
    jsp的四种范围
    jsp的两种跳转方式和区别
  • 原文地址:https://www.cnblogs.com/BOZHAO/p/13375321.html
Copyright © 2020-2023  润新知