[BZOJ]4170: 极光 2989: 数列 CDQ分治+树状数组

来源:互联网 发布:极速淘宝秒杀 编辑:程序博客网 时间:2024/05/22 01:45

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的对数。(某位置多次修改为同样的数值,按多次统计)

题解:

一开始看,分四种情况讨论的话是四维偏序,后来灵机一动,把它看做平面上的点的话,求的就是距离不超过k的有多少个点,这个区域恰好是一个菱形,那么把坐标系旋转一下,就可以变成询问一个矩形内数的和了,那么就和简单题的方法一样了。(不知道为什么数组要莫名开大)

代码:

#include<bits/stdc++.h>using namespace std;#define LL long longconst int Maxq=150010;int read(){    int x=0,f=1;char ch=getchar();    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}    while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();    return x*f;}int n,Q,a[600100],cnt,idcnt=0;int X(int x,int y){return x+y-1;}int Y(int x,int y){return n-x+y;}LL ans[500100];struct Opt{int x,y,k,type,id;}q[Maxq],q1[Maxq<<2],temp[Maxq<<2];int s[4000010];void add(int x,int y){if(x<=0)return;for(;x<=4000000;x+=(x&-x))s[x]+=y;}LL getsum(int x){LL re=0;for(;x>0;x-=(x&-x))re+=(LL)(s[x]);return re;}int List[Maxq<<2];void solve(int l,int r){    if(l==r)return;    int mid=l+r>>1;    solve(l,mid);solve(mid+1,r);    int i=l,j=mid+1,len=0,o=0;    while(i<=mid&&j<=r)    {        if(q1[i].x<q1[j].x||(q1[i].x==q1[j].x&&q1[i].type<q1[j].type))        {            if(q1[i].type==1)add(q1[i].y,1),List[++o]=q1[i].y;            temp[++len]=q1[i++];        }        else        {            if(q1[j].type==2)ans[q1[j].id]+=getsum(q1[j].y);            else if(q1[j].type==3)ans[q1[j].id]-=getsum(q1[j].y);            temp[++len]=q1[j++];        }    }    int t=i;    while(i<=mid)temp[++len]=q1[i++];    while(j<=r)    {        if(q1[j].type==2)ans[q1[j].id]+=getsum(q1[j].y);        else if(q1[j].type==3)ans[q1[j].id]-=getsum(q1[j].y);        temp[++len]=q1[j++];    }    for(int p=1;p<=o;p++)add(List[p],-1);    for(int p=1;p<=len;p++)q1[l+p-1]=temp[p];}int main(){    n=read(),Q=read();    for(int i=1;i<=n;i++)q[i].type=1,q[i].x=i,q[i].y=a[i]=read();    for(int i=1;i<=Q;i++)    {        char op[8];        scanf("%s",op);        int u1=read(),u2=read(),t=i+n;        if(op[0]=='M')q[t].type=1,q[t].x=u1,q[t].y=u2,a[u1]=u2;        else q[t].type=2,q[t].x=u1,q[t].y=a[u1],q[t].k=u2,q[t].id=++idcnt;    }    for(int i=1;i<=n;i++)q1[i]=q[i],q1[i].x=X(q[i].x,q[i].y),q1[i].y=Y(q[i].x,q[i].y);cnt=n;    for(int i=1+n;i<=Q+n;i++)    {        if(q[i].type==1)q1[++cnt]=q[i],q1[cnt].x=X(q[i].x,q[i].y),q1[cnt].y=Y(q[i].x,q[i].y);        else        {            int X1=q[i].x,Y1=q[i].y-q[i].k,X2=q[i].x,Y2=q[i].y+q[i].k;            int x1=X(X1,Y1),y1=Y(X1,Y1),x2=X(X2,Y2),y2=Y(X2,Y2);            q1[++cnt].type=2;q1[cnt].x=x2;q1[cnt].y=y2;            q1[++cnt].type=2;q1[cnt].x=x1-1;q1[cnt].y=y1-1;            q1[++cnt].type=3;q1[cnt].x=x1-1;q1[cnt].y=y2;            q1[++cnt].type=3;q1[cnt].x=x2;q1[cnt].y=y1-1;            q1[cnt].id=q1[cnt-1].id=q1[cnt-2].id=q1[cnt-3].id=q[i].id;        }    }    solve(1,cnt);    for(int i=1;i<=idcnt;i++)printf("%lld\n",ans[i]);}
阅读全文
2 0
原创粉丝点击