您的位置:首页 > 其它

【bzoj2989】【数列】【cdq分治+树状数组】

2016-06-29 11:46 225 查看

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

Input

第1行两个整数n,q。分别表示数列长度和操作数。
第2行n个正整数,代表初始数列。
第3--q+2行每行一个操作。

Output

对于每次询问操作,输出一个非负整数表示答案

Sample Input

3 5

2 4 3

Query 2 2

Modify 1 3

Query 2 2

Modify 1 2

Query 1 1

Sample Output

2

3

3

HINT

N<=60000 修改操作数<=40000 询问<=50000 Max{a[i]}含修改<=100000
题解:
         首先可以发现所谓的可持久化看成加点即可.
         把(x,a[x])看成一个点.然后我们把曼哈顿距离转化成切比雪夫距离.
         问题就变成了每次询问一个矩形中有多少点.
         把一个矩形拆成4个然后cdq分治+树状数组即可.
         注意坐标不一定都在第一象限,拆分矩形的时候判断一下即可.
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define N 100010
#define M 200010
using namespace std;
int n,m,a
,tot,x,y,k,cnt,mx,t[M<<2],ans[M];
char ch[10];
struct use{int x,y,id,k,v,p;}q[M<<2],p[M<<2];
int read(){
int x(0);char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x;
}
void add(int kind,int p,int x,int y){
int xx=x-y,yy=x+y;mx=max(yy,mx);//cout<<xx<<' '<<yy<<endl;
if (kind==0){q[++tot].x=xx;q[tot].y=yy;q[tot].id=tot;q[tot].k=kind;}
else{
int x1=xx-k,y1=yy-k,x2=xx+k,y2=yy+k;mx=max(mx,y2);
if (y1>0){q[++tot].id=tot;q[tot].k=kind;q[tot].x=x1-1;q[tot].y=y1-1;q[tot].v=1;q[tot].p=p;}
q[++tot].id=tot;q[tot].k=kind;q[tot].x=x1-1;q[tot].y=y2;q[tot].v=-1;q[tot].p=p;
if (y1>0){q[++tot].id=tot;q[tot].k=kind;q[tot].x=x2;q[tot].y=y1-1;q[tot].v=-1;q[tot].p=p;}
q[++tot].id=tot;q[tot].k=kind;q[tot].x=x2;q[tot].y=y2;q[tot].v=1;q[tot].p=p;
}
}
bool cmp(use a,use b){
if (a.x==b.x){
if (a.y==b.y) return a.id<b.id;
else return a.y<b.y;
}
return a.x<b.x;
}
int lowbit(int x){return x&(-x);}
void add(int x,int v){for (int i=x;i<=mx;i+=lowbit(i)) t[i]+=v;}
int query(int x){
int ans(0);
for (int i=x;i;i-=lowbit(i)) ans+=t[i];
return ans;
}
void solve(int l,int r){
if (l==r) return;
int mid=(l+r)>>1,l1=l,l2=mid+1;
for (int i=l;i<=r;i++){
if (q[i].id<=mid&&!q[i].k) add(q[i].y,1);
if (q[i].id>mid&&q[i].k) ans[q[i].p]+=query(q[i].y)*q[i].v;
}
for (int i=l;i<=r;i++)
if (q[i].id<=mid&&!q[i].k) add(q[i].y,-1);
for (int i=l;i<=r;i++)
if (q[i].id<=mid) p[l1++]=q[i];
else p[l2++]=q[i];
for (int i=l;i<=r;i++) q[i]=p[i];
solve(l,mid);solve(mid+1,r);
}
int main(){
n=read();m=read();
for (int i=1;i<=n;i++)
a[i]=read(),add(0,0,i,a[i]);
for (int i=n+1;i<=n+m;i++){
scanf("%s",ch);
if (ch[0]=='M') x=read(),y=read(),add(0,0,x,y),a[x]=y;
else x=read(),k=read(),add(1,++cnt,x,a[x]);
}
sort(q+1,q+tot+1,cmp);mx++;
solve(1,tot);
for (int i=1;i<=cnt;i++) printf("%d\n",ans[i]);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: