modify操作就相当于加点其实
可以把坐标系旋转一下,点(x,y)变成(x+y,-x+y),这样查询曼哈顿距离<=k的就变成查边长为2k的正方形里的点的个数
二维线段树搞搞即可
其实讲道理的话不转坐标系直接KD树搞上应该也是可以的
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<algorithm>
#include<iomanip>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<bitset>
#include<set>
#include<map>
using namespace std;
#define MAXN 200010
#define MAXM 20000010
#define INF 1000000000
#define eps 1e-8
#define MOD 1000000007
#define ll long long
int n,m;
int lim=200000;
int liml=-100000,limr=100000;
int a[MAXN];
int siz[MAXM];
int son[MAXM][2];
int rt[MAXN<<2];
int tot;
void change(int &x,int y,int z,int p){
if(!x){
x=++tot;
}
siz[x]++;
if(y==z){
return ;
}
int mid=y+z>>1;
if(p<=mid){
change(son[x][0],y,mid,p);
}else{
change(son[x][1],mid+1,z,p);
}
}
void tochange(int x,int y,int z,int p,int pp){
change(rt[x],liml,limr,pp);
if(y==z){
return ;
}
int mid=y+z>>1;
if(p<=mid){
tochange(x<<1,y,mid,p,pp);
}else{
tochange(x<<1|1,mid+1,z,p,pp);
}
}
int ask(int x,int y,int z,int l,int r){
if(l<liml){
l=liml;
}
if(r>limr){
r=limr;
}
if(!x){
return 0;
}
if(y==l&&z==r){
return siz[x];
}
int mid=y+z>>1;
if(r<=mid){
return ask(son[x][0],y,mid,l,r);
}else if(l>mid){
return ask(son[x][1],mid+1,z,l,r);
}else{
return ask(son[x][0],y,mid,l,mid)+ask(son[x][1],mid+1,z,mid+1,r);
}
}
int toask(int x,int y,int z,int l,int r,int L,int R){
if(l<1){
l=1;
}
if(r>lim){
r=lim;
}
if(y==l&&z==r){
return ask(rt[x],liml,limr,L,R);
}
int mid=y+z>>1;
if(r<=mid){
return toask(x<<1,y,mid,l,r,L,R);
}else if(l>mid){
return toask(x<<1|1,mid+1,z,l,r,L,R);
}else{
return toask(x<<1,y,mid,l,mid,L,R)+toask(x<<1|1,mid+1,z,mid+1,r,L,R);
}
}
int main(){
int i,x,y;
char o[10];
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++){
scanf("%d",&a[i]);
tochange(1,1,lim,i+a[i],-i+a[i]);
}
while(m--){
scanf("%s%d%d",o,&x,&y);
if(o[0]=='Q'){
printf("%d\n",toask(1,1,lim,x+a[x]-y,x+a[x]+y,-x+a[x]-y,-x+a[x]+y));
}
if(o[0]=='M'){
a[x]=y;
tochange(1,1,lim,x+y,-x+y);
}
}
return 0;
}
/*
*/