BZOJ-2989: 数列

[文章目录]

Description

给定一个长度为n的正整数数列a[i]。
定义2个位置的graze值为两者位置差与数值差的和,即graze(x,y)=|x-y|+|a[x]-a[y]|。2种操作(k都是正整数):
1.Modify x k:将第x个数的值修改为k。
2.Query x k:询问有几个i满足graze(x,i)<=k。因为可持久化数据结构的流行,询问不仅要考虑当前数列,还要考虑任意历史版本,即统计任意位置上出现过的任意数值与当前的a[x]的graze值<=k的对数。(某位置多次修改为同样的数值,按多次统计)

查询的形式为到定点的曼哈顿距离,KD-tree维护矩形内点的个数,修改历史版本看成加点即可。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
int n,m,d,rot,a[61000],cg[101000],cgg;
double arf=0.75;
struct KD_tree
{
    int p[2],mi[2],mx[2],ls,rs,siz;
    void clear()
    {
        mi[0]=mx[0]=p[0];
        mi[1]=mx[1]=p[1];
        siz=1; ls=rs=0;
    }
}t[101000];
bool operator < (const KD_tree x,const KD_tree y)
{
    return x.p[d]==y.p[d] ? x.p[d^1]<y.p[d^1] : x.p[d]<y.p[d];
}
bool cmp(int x,int y){return t[x]<t[y];}
void pushup(int p,int k)
{
    t[p].mi[0]=min(t[p].mi[0],t[k].mi[0]);
    t[p].mx[0]=max(t[p].mx[0],t[k].mx[0]);
    t[p].mi[1]=min(t[p].mi[1],t[k].mi[1]);
    t[p].mx[1]=max(t[p].mx[1],t[k].mx[1]);
    t[p].siz+=t[k].siz;
}
int build(int l,int r,int fl)
{
    int mid=(l+r)>>1; d=fl;
    nth_element(cg+l,cg+mid,cg+r+1,cmp);
    int re=cg[mid];
    if(l<mid) pushup(re,t[re].ls=build(l,mid-1,fl^1));
    if(r>mid) pushup(re,t[re].rs=build(mid+1,r,fl^1));
    return re;
}
void flatten(int p)
{
    if(!p) return ;
    flatten(t[p].ls); flatten(t[p].rs);
    t[p].clear(); cg[++cgg]=p;
}
void rebuild(int &p,int D)
{
    cgg=0; flatten(p);
    p=build(1,cgg,D);
}
void insert(int &p,int k,int fl,int D)
{
    if(!p) {p=k; return ;}
    pushup(p,k); d=D;
    if(t[k]<t[p])
    {
        if(!fl&&t[t[p].ls].siz+1>t[p].siz*arf) insert(t[p].ls,k,1,D^1),rebuild(p,D);
        else insert(t[p].ls,k,fl,D^1);
    }
    else
    {
        if(!fl&&t[t[p].rs].siz+1>t[p].siz*arf) insert(t[p].rs,k,1,D^1),rebuild(p,D);
        else insert(t[p].rs,k,fl,D^1);
    }
}
int query(int p,int x,int dx,int y,int dy)
{
    if(!p||x>t[p].mx[0]||dx<t[p].mi[0]||y>t[p].mx[1]||dy<t[p].mi[1]) return 0;
    if(x<=t[p].mi[0]&&dx>=t[p].mx[0]&&y<=t[p].mi[1]&&dy>=t[p].mx[1]) return t[p].siz;
    int re=0;
    if(t[p].p[0]>=x&&t[p].p[0]<=dx&&t[p].p[1]>=y&&t[p].p[1]<=dy) re++;
    re+=query(t[p].ls,x,dx,y,dy)+query(t[p].rs,x,dx,y,dy);
    return re;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i)
    {
        scanf("%d",a+i);
        t[i].p[0]=i+a[i];
        t[i].p[1]=i-a[i];
        t[i].clear();
        cg[i]=i;
    }
    rot=build(1,n,0); char sw[10]; int x,k;
    while(m--)
    {
        scanf("%s%d%d",sw,&x,&k);
        if(sw[0]=='M')
        {
            a[x]=k; n++; t[n].p[0]=x+k; t[n].p[1]=x-k; t[n].clear();
            insert(rot,n,0,0);
        }
        else printf("%d\n",query(rot,x+a[x]-k,x+a[x]+k,x-a[x]-k,x-a[x]+k));
    }
    return 0;
}

发表评论

邮箱地址不会被公开。 必填项已用*标注