BZOJ 2989 数列

CDQ分治+树状数组

注意到这题修改操作对询问的贡献独立,且修改之间互不影响,考虑CDQ分治。用左边的修改更新右边,只需按x排序所有事件点,树状数组维护y轴即可。

不知道KD树能不能搞一搞?

#include<cstdio>
#include<algorithm>
#define lowbit(_i) (_i&-_i)
#define N 800005
#define BASE 400005
using namespace std;
namespace runzhe2000
{
    int read()
    {
        int r = 0; char c = getchar();
        for(; c < '0' || c > '9'; c = getchar());
        for(; c >='0' && c <='9'; r = r*10+c-'0', c = getchar());
        return r;
    }
    char str[10];
    int n, Q, a[N], qcnt, ans[N];
    struct BIT
    {
        int t[N];
        void mod(int x, int v){for(;x<N;x+=lowbit(x)) t[x] += v;}
        int _que(int x){int r = 0; for(;x;x-=lowbit(x)) r += t[x]; return r;}
        int que(int l, int r){return _que(r) - _que(l-1);}
    } bit;
    struct que
    {
        int type, x, y, d, id; // 0 insert 1 query // 1 add_query -1 del_query
        bool operator < (const que &that) const
        {
            if(x != that.x) return x < that.x;
            else return type > that.type;
        }
    }q[N], qq[N<<1];
    void dc(int l, int r)
    {
        if(l == r) return; int mid = (l+r)>>1, qqcnt = 0;
        for(int i = l; i <= mid  ; i++) if(!q[i].type) qq[++qqcnt] = q[i];
        for(int i = mid+1; i <= r; i++) if(q[i].type)
        {
            qq[++qqcnt] = (que){1 , q[i].x - q[i].d, q[i].y, q[i].d, q[i].id};
            qq[++qqcnt] = (que){-1, q[i].x + q[i].d, q[i].y, q[i].d, q[i].id};
        }
        sort(qq+1, qq+1+qqcnt);
        for(int i = 1; i <= qqcnt; i++)
        {
            if(qq[i].type == 0) bit.mod(qq[i].y, 1);
            else if(qq[i].type == 1) ans[qq[i].id] -= bit.que(qq[i].y - qq[i].d, qq[i].y + qq[i].d);
            else ans[qq[i].id] += bit.que(qq[i].y - qq[i].d, qq[i].y + qq[i].d);
        }
        for(int i = 1; i <= qqcnt; i++) if(qq[i].type == 0) bit.mod(qq[i].y, -1);
        dc(l,mid); dc(mid+1,r);
    }
    void main()
    {
        n = read(); Q = read();
        for(int i = 1; i <= n; i++) 
        {
            a[i] = read();
            q[++qcnt] = (que){0, i+a[i]+BASE, i-a[i]+BASE, 0, 0};
        }
        for(int i = 1; i <= Q; i++)
        {
            scanf("%s",str);
            if(str[0] == 'Q'){int p = read(); q[++qcnt] = (que){1, p+a[p]+BASE, p-a[p]+BASE, read(), i};}
            else {int p = read(); a[p] = read(); q[++qcnt] = (que){0, p+a[p]+BASE, p-a[p]+BASE, 0, 0};}
        }
        dc(1,qcnt);
        for(int i = 1; i <= Q; i++) if(ans[i]) printf("%d\n",ans[i]);
    }
}
int main()
{
    runzhe2000::main();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值