• 2019~2020icpc亚洲区域赛徐州站H. Yuuki and a problem


    2019~2020icpc亚洲区域赛徐州站H. Yuuki and a problem

    题意:

    给定一个长度为(n)的序列,有两种操作:

    • 1:单点修改。
    • 2:查询区间([L,R])范围内所有子集和中没出现的最小正整数。

    思路:

    对于维护序列的问题大概率是数据结构的题目了,先确定一下题目的性质。

    操作2需要我们提取([l,r])范围内的值,这可以用主席树解决,同时需要带修,所以可以用树状数组套主席树完成。

    确定是树套树后,考虑怎么维护操作2。

    我们考虑一个节点,先看看能不能表示成1,如果这个节点代表的区间一个1都没有,那他的答案为1。

    假设答案已经可以构成([1,x])了。

    考虑当前节点代表的区间内值为([1,x+1])的数字的和为sum。

    那么我们就可以构成([1,sum])这个区间了,如果(sum==x),那么答案就是(x+1)

    这个过程可以暴力跑,因为他是一个斐波那契数列,不到多少项就到2e5了。

    所以我们操作2就相当于是模拟这样一个过程。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int maxn = 2e5+10;
    int n, m, len;
    ll a[maxn];
    
    inline int lowbit(int x){
        return x&(-x);
    }
    
    ll sum[maxn*80];
    int ls[maxn*80];
    int rs[maxn*80];
    int rt[maxn*80];
    int tot;
    
    void update_SgT(int &rt, int l, int r, int x, int val)
    {
        if(!rt) rt = ++tot;
        if(l == r)
        {
            sum[rt] += val;
            return;
        }
        int mid = (l+r)>>1;
        if(x <= mid) update_SgT(ls[rt], l, mid, x, val);
        else update_SgT(rs[rt], mid+1, r, x, val);
        sum[rt] = sum[ls[rt]] + sum[rs[rt]];
    }
    
    void update_BIT(int pos, int x, int val)
    {
        for(int i = pos; i <= n; i += lowbit(i))
            update_SgT(rt[i], 1, len, x, val);
    }
    
    int rt1[maxn], rt2[maxn], cnt1, cnt2;
    void locate(int l, int r)
    {
        cnt1 = cnt2 = 0;
        for(int i = l-1; i; i -= lowbit(i))
            rt1[++cnt1] = rt[i];
        for(int i = r; i; i -= lowbit(i))
            rt2[++cnt2] = rt[i];
    }
    
    ll ask(int l, int r, int k)
    {
        ll ans = 0;
        if(r == k)
        {
            for(int i = 1; i <= cnt1; i++)
                ans -= sum[rt1[i]];
            for(int i = 1; i<= cnt2; i++)
                ans += sum[rt2[i]];
            return ans;
        }
    
        int mid = (l+r)>>1;
        if(k <= mid)
        {
            for(int i = 1; i <= cnt1; i++)
                rt1[i] = ls[rt1[i]];
            for(int i = 1; i <= cnt2; i++)
                rt2[i] = ls[rt2[i]];
            return ask(l, mid, k);
        }
        else
        {
            for(int i = 1; i <= cnt1; i++)
                ans -= sum[ls[rt1[i]]];
            for(int i = 1; i <= cnt2; i++)
                ans += sum[ls[rt2[i]]];
    
            for(int i = 1; i <= cnt1; i++)
                rt1[i] = rs[rt1[i]];
            for(int i = 1; i <= cnt2; i++)
                rt2[i] = rs[rt2[i]];
            return ans + ask(mid+1, r, k);
        }
    }
    
    
    int main()
    {
        scanf("%d%d", &n, &m);
        len = maxn-10;
        for(int i = 1; i <= n; i++)
            scanf("%lld", &a[i]);
    
        for(int i = 1; i <= n; i++)
            update_BIT(i, a[i], a[i]);
    
        for(int i = 1, op, x, y; i <= m; i++)
        {
            scanf("%d%d%d", &op, &x, &y);
            if(op == 1) //修改操作
            {
                update_BIT(x, a[x], -a[x]);
                a[x] = y;
                update_BIT(x, y, y);
            }
            else
            {
                ll now = 1;
                ll s = 0;
                while(true)
                {
                    locate(x, y);
                    int t = min(now, 200000ll);
                    ll tmp = ask(1, len, t);
                    if(tmp == s)
                    {
                        printf("%lld
    ", now);
                        break;
                    }
                    s = tmp, now = s+1;
                }
            }
        }
    
        return 0;
    }
    
  • 相关阅读:
    如何计算二进制数的取值范围
    理解网络请求中的连接超时和读取超时
    两行代码玩转Spring Data排序和分页
    面试必问Elasticsearch倒排索引原理
    你知道Java的四种引用类型吗
    抛弃配置后的Spring终极教程
    Python学习第二篇
    Python
    关于always块内for循环的执行方式
    三态门实现“一读多写”总线结构
  • 原文地址:https://www.cnblogs.com/zxytxdy/p/12375629.html
Copyright © 2020-2023  润新知