zoukankan      html  css  js  c++  java
  • 【计蒜客42547/2019ICPC徐州H】Yuuki and a problem(MEX性质+树套树)

    题目链接:https://nanti.jisuanke.com/t/42547

    题目大意

    给定一个序列,有以下几种操作:

    1. 将第 (x) 位置的数修改为 (y)

    2. 询问区间 ([L, R]),问其子集之和的 MEX。

    思路

    首先有一个性质:先看看是否存在 (1)。若没有 (1),则表明必然无法凑出 (1),那么答案就是 (1)

    然后假设上一次求出来的和的值为 (x),表明 ([1,x]) 都可以通过子集表示出来。再求 ([1,x+1]) 的和,若和 ([1,x]) 求和的值相等,则表示 (x+1) 不能被表示。

    最坏情况为斐波那契数列。

    带修区间+小于某个树的值查询=树状数组套主席树!

    花絮

    因为并没有很好地使用之前已有的节点导致一直MLE,主席树盲目创建结点不可取

    AC代码

    #include <bits/stdc++.h>
    
    typedef long long ll;
    using namespace std;
    const int MAXN = 2e5 + 100;
    
    class DS {
    public:
        // HJT begin
        int ch[MAXN * 150][2], tot = 0;
        ll sum[MAXN * 150];
    
        inline void push_up(int rt) {
            sum[rt] = sum[ch[rt][0]] + sum[ch[rt][1]];
        }
    
        int update(int rt, int pos, int val, int be, int en) {
            int nrt = rt;
            if (!rt) {
                nrt = ++tot;
                ch[nrt][0] = ch[nrt][1] = sum[nrt] = 0;
            }
    
    //        int nrt = ++tot;
    //        ch[nrt][0] = ch[nrt][1] = sum[nrt] = 0;
            if (be == en) {
                sum[nrt] += (ll) be * val;
                return nrt;
            }
            int mid = (be + en) >> 1;
            if (pos <= mid) {
                ch[nrt][0] = update(ch[rt][0], pos, val, be, mid);
                ch[nrt][1] = ch[rt][1];
            } else {
                ch[nrt][0] = ch[rt][0];
                ch[nrt][1] = update(ch[rt][1], pos, val, mid + 1, en);
            }
            push_up(nrt);
            return nrt;
        }
    
        // HJT end
        int n, c_len, root[MAXN];
    
        void init(int _n, int _c_len) {
            c_len = _c_len, n = _n;
            for (int i = 1; i <= c_len; i++) root[i] = i;
            tot = c_len;
        }
    
        inline int lowbit(int x) { return x & (-x); }
    
        void insert(int pos, int pos_val, int val) {
            for (int i = pos; i <= n; i += lowbit(i)) root[i] = update(root[i], pos_val, val, 1, c_len);
        }
    
        int t1[MAXN], t2[MAXN], n1, n2;
    
        inline ll SUM(int R, int be, int en) {
            if (be == en) {
                ll ans = 0;
                for (int i = 1; i <= n1; i++) ans -= sum[t1[i]];
                for (int i = 1; i <= n2; i++) ans += sum[t2[i]];
                return ans;
            }
    
            int mid = (be + en) >> 1;
            ll ans = 0;
            if (mid >= R) {
                for (int i = 1; i <= n1; i++) t1[i] = ch[t1[i]][0];
                for (int i = 1; i <= n2; i++) t2[i] = ch[t2[i]][0];
                return SUM(R, be, mid);
            } else {
                for (int i = 1; i <= n1; i++) ans -= sum[ch[t1[i]][0]];
                for (int i = 1; i <= n2; i++) ans += sum[ch[t2[i]][0]];
                for (int i = 1; i <= n1; i++) t1[i] = ch[t1[i]][1];
                for (int i = 1; i <= n2; i++) t2[i] = ch[t2[i]][1];
                return ans + SUM(R, mid + 1, en);
            }
        }
    
        ll query(int l, int r, int x) {
            n1 = n2 = 0;
            for (int i = l - 1; i >= 1; i -= lowbit(i)) t1[++n1] = root[i];
            for (int i = r; i >= 1; i -= lowbit(i)) t2[++n2] = root[i];
            return SUM(x, 1, c_len);
        }
    } tree;
    
    int a[MAXN];
    
    int main() {
        //freopen("test.in", "r", stdin);
        int n, q;
        scanf("%d%d", &n, &q);
        for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
        tree.init(n, 2e5);
        for (int i = 1; i <= n; i++) {
         
            tree.insert(i, a[i], 1);
        }
    
        while (q--) {
            int opt;
            scanf("%d", &opt);
            if (opt == 1) {
                int x, y;
                scanf("%d%d", &x, &y);
                tree.insert(x, a[x], -1);
                a[x] = y;
                tree.insert(x, a[x], 1);
            } else {
                int L, R;
                scanf("%d%d", &L, &R);
    
                ll now = 1, sum = 0;
                while (1) {
                    int t = min(now, (ll) 2e5);
                    ll tmp = tree.query(L, R, t);
                    if (tmp == sum) {
                        printf("%lld
    ", now);
                        break;
                    } else {
                        sum = tmp, now = sum + 1;
                    }
                }
            }
        }
       // fclose(stdin);
    }
    
  • 相关阅读:
    sqlserver判断是否为数字的函数
    vs2013 旗舰版 密钥
    HttpWebRequest类与HttpRequest类的区别
    C#中HttpWebRequest的用法详解
    SQL Server查询优化方法(查询速度慢的原因很多,常见如下几种)
    随机数Random
    PadLeft 补零
    delphi Firemonkey ListBoxItem自绘
    windows自带杀毒防火墙
    IIS 更新EXE文件
  • 原文地址:https://www.cnblogs.com/tudouuuuu/p/14145080.html
Copyright © 2011-2022 走看看