zoukankan      html  css  js  c++  java
  • 2021美团杯A.数据结构

    补题:2021美团杯A.数据结构
    比赛一开始看到不同数个数,张口主席树求区间不同数个数瞬间带歪队友,自己也在错误的道路上越走越远。
    在中后期重新阅读题面发现每次询问的是全局不同数的个数,想到了最多只有(n+1)个数,对于每一次询问,我去计算有多少数会被删除,有多少数会被增加。无奈题刷少了,没想到统计不出现数的个数。
    思路
    彩蛋:学习了邓老师的代码,结果在看他代码的时候发现了一个手误情况,直接手造hack数据给了jls,成为了热心网友hack了邓老师,邓老师AK IOI,那么我hack邓老师,四舍五入就是我hack IOI(狗头保命)。然后发现我队也抽到了阳光普照奖2333333。
    对于一个数(x),考虑其最左出现的位置(l_x),最右出现的位置(r_x),那么首先就确定每次询问的(l,r)满足(lleq l_x, r_x leq r)。然后考虑(x-1)的出现位置,若在(l_x leq pos leq r_x)中出现,那么(x)永远存在,其它情况就是会出现(pos_t leq l_x leq r_x leq pos_{t+1})。然后到这一步在赛中就不会维护了。
    根据上面的这个不等式,我们发现当(pos_t leq l leq l_x,r_x leq r leq pos_{t+1})时这个值会减去,那么只要用类似差分的思想,在(r_x)上设置([pos_t+1,l_x])这一段(+1),在(pos_{t+1})上对([pos_t+1,l_x])这一段(-1)。这样就对右边的这一块进行了维护。
    在输入完查询之后,我们从第一个位置出发,对于当前需要更新的位置(i),我们可以知道对于某个数我们在([l,r])之间对其有一个更新,那么就把左边的这个([l,r])更新到树状数组中,表示当我的右区间下标为(i)时,此时左区间([l,r])有一个数会删除/增加。然后对于每一个询问查询一下当前右区间为(i)时,有多少个值在左区间不出现。
    然后对于原始数组没有出现过的数字,那么直接把(x-1)的每一个不相交的区间更新进去即可。
    代码
    代码中注释掉的是邓老师的写法。

    #include<bits/stdc++.h>
    using namespace std;
    
    typedef long long LL;
    typedef pair<int, int> PII;
    typedef unsigned long long ULL;
    #define x first
    #define y second
    const int N = 1e6 + 10, M = 13331;
    const double PI = acos(-1.0);
    const double eps = 1e-5;
    const int mod = 1000000007;
    const int inf = 0x3f3f3f3f;
    const LL INF = 0x3f3f3f3f3f3f3f3f;
    #define gcd __gcd
    
    vector<int> v[N];
    int l[N], r[N];
    struct Node {
        int l, r, v;
    };
    vector<Node> vec[N];
    int tr[N], res[N];
    int n, m;
    vector<PII> que[N];
    int a[N];
    
    int lowbit(int x) {
        return x & -x;
    }
    
    void add(int p, int x) {
        for(int i = p; i <= n; i += lowbit(i)) {
            tr[i] += x;
        }
    }
    
    int query(int x) {
        int res = 0;
        for(int i = x; i > 0; i -= lowbit(i)) {
            res += tr[i];
        }
        return res;
    }
    
    void update(int l1, int r1, int l2, int r2, int val) {
        if(l1 > r1 || l2 > r2) return;
        // printf("val = %d %d %d %d %d
    ", val, l1, r1, l2, r2);
        vec[l2].push_back({l1, r1, 1});
        vec[r2 + 1].push_back({l1, r1, -1});
    }
    
    void solve() {
        scanf("%d%d", &n, &m);
        for(int i = 0; i <= n + 1; i++) {
            v[i].push_back(0);
            l[i] = n + 1;
            r[i] = 0;
        }
        for(int i = 1; i <= n; i++) {
            scanf("%d", &a[i]);
            l[a[i]] = min(l[a[i]], i);
            r[a[i]] = max(r[a[i]], i);
            v[a[i]].push_back(i);
        }
        for(int i = 0; i <= n + 1; i++) {
            v[i].push_back(n + 1);
        }
    
        for(int i = 1; i <= n + 1; i++) {
            // 不存在
            if(l[i] == n + 1) {
                for(int j = 0; j < v[i - 1].size() - 1; j++) {
                    int l = v[i - 1][j] + 1, r = v[i - 1][j + 1] - 1;
                    update(l, r, l, r, i);
                }
            }
            else {
                int L = 0, R = n + 1;
                bool flag = false;
                for(auto x : v[i - 1]) {
                    if(l[i] <= x && x <= r[i]) {
                        flag = true;
                        break;
                    }
                    if(x < l[i]) L = max(x, L);
                    if(x > r[i]) R = min(x, R);
                }
                if(flag) continue;
                update(L + 1, l[i], r[i], R - 1, i);
            }
        }
    
        // for(int i = 1; i <= n + 1; i++) {
        //     int l = n, r = 1;
        //     for(auto x : v[i]) {
        //         l = min(l, x);
        //         r = max(r, x);
        //     }
        //     vector<int> tmp; tmp.push_back(0);
        //     for(auto x : v[i - 1]) tmp.push_back(x);
        //     tmp.push_back(n + 1);
        //     for(int j = 0; j < tmp.size() - 1; j++) {
        //         int L = tmp[j], R = tmp[j + 1];
        //         // printf("i = %d, l = %d, r = %d, L = %d, R = %d
    ", i, l, r, L, R);
        //         // printf("i = %d, %d %d %d %d
    ", L + 1, min(l, R - 1), max(R, L + 1), R - 1);
        //         update(L + 1, min(l, R - 1), max(r, L + 1), R - 1, i);
        //     }
        // }
        for(int i = 1; i <= m; i++) {
            int l, r;
            scanf("%d%d", &l, &r);
            que[r].push_back({l, i});
        }
        for(int i = 1; i <= n; i++) {
            for(int j = 0; j < vec[i].size(); j++) {
                int l = vec[i][j].l, r = vec[i][j].r, x = vec[i][j].v;
                // printf("l = %d, r = %d
    ", l, r);
                add(l, x);
                add(r + 1, -x);
            }
            for(int j = 0; j < que[i].size(); j++) {
                int x = que[i][j].x, id = que[i][j].y;
                res[id] = n + 1 - query(x);
            }
        }
        for(int i = 1; i <= m; i++) {
            printf("%d
    ", res[i]);
        }
    }
    
    int main() {
        #ifndef ONLINE_JUDGE
        freopen("in.txt", "r", stdin);
        // freopen("out.txt", "w", stdout);
        #endif // ONLINE_JUDGE
    
        // int t; cin >> t; while(t--)
        solve();
        return 0;
    }
    
  • 相关阅读:
    wget(转)
    852. Peak Index in a Mountain Array
    617. Merge Two Binary Trees
    814. Binary Tree Pruning
    657. Judge Route Circle
    861. Score After Flipping Matrix
    832. Flipping an Image
    461. Hamming Distance
    654. Maximum Binary Tree
    804. Unique Morse Code Words
  • 原文地址:https://www.cnblogs.com/ZX-GO/p/15009102.html
Copyright © 2011-2022 走看看