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\n", now);
                    break;
                }
                s = tmp, now = s+1;
            }
        }
    }

    return 0;
}
posted @ 2020-02-28 07:59  zhaoxiaoyun  阅读(796)  评论(0编辑  收藏  举报