二维线段树搞搞。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int read()
{
char ch=getchar();int f=0;
while(ch<'0'||ch>'9')ch=getchar();
while(ch>='0'&&ch<='9'){f=(f<<1)+(f<<3)+ch-'0';ch=getchar();}
return f;
}
int n,m;
int lim=200000;
int liml=-100000,limr=100000;
int a[200005],size[20000005],son[20000005][2],rt[800005],tot;
void change(int &x,int y,int z,int p)
{
if(!x)
{
x=++tot;
}
size[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 size[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 x,y;
char o[10];
n=read(),m=read();
for(int i=1;i<=n;i++)
{
a[i]=read();
tochange(1,1,lim,i+a[i],-i+a[i]);
}
while(m--)
{
scanf("%s",o);
x=read(),y=read();
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);
}
}
}