题目
Description
“若是万一琪露诺(俗称rhl)进行攻击,什么都好,冷静地回答她的问题来吸引她。对方表现出兴趣的话,那就慢
慢地反问。在她考虑答案的时候,趁机逃吧。就算是很简单的问题,她一定也答不上来。”
–《上古之魔书》
天空中出现了许多的北极光,这些北极光组成了一个长度为n的正整数数列a[i],远古之魔书上记载到:2个位置的g
raze值为两者位置差与数值差的和:
$graze(x,y)=\vert x-y\vert +\vert a[x]-a[y]\vert$。
要想破解天罚,就必须支持2种操作(k都是正整数):
Modify x k:将第x个数的值修改为k。
Query x k:询问有几个i满足graze(x,i)<=k。
由于从前的天罚被圣王lmc破解了,所以rhl改进了她的法术,询问不仅要考虑当前数列,还要考虑任意历史版本,
即统计任意位置上出现过的任意数值与当前的a[x]的graze值<=k的对数。(某位置多次修改为同样的数值,按多次
统计)
Input
第1行两个整数n,q。分别表示数列长度和操作数。
第2行n个正整数,代表初始数列。
第3~q+2行每行一个操作。
N<=40000, 修改操作数<=60000, 询问操作数<=10000, Max{a[i]}(含修改)<=80000
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
题解
代码
# include<iostream>
# include<cstring>
# include<cstdio>
# include<algorithm>
# define tl s[k].l
# define tr s[k].r
# define mid (l+r>>1)
using namespace std;
const int MAX=1e5+5;
const double aph=0.75;
int n,Q,D,Top,tot,rt;
int st[MAX],a[MAX];
struct KD_Tree{
int l,r,siz;
int d[2],mx[2],mi[2];
void add(int x,int y) {d[0]=mx[0]=mi[0]=x,d[1]=mx[1]=mi[1]=y,l=r=0,siz=1;}
bool operator< (const KD_Tree &a)
const{
if(d[D]!=a.d[D]) return d[D]<a.d[D];
return d[D^1]<a.d[D^1];
}
}s[MAX],s1[MAX];
char A[10];
int max(int x,int y) {return x>y?x:y;}
int min(int x,int y) {return x<y?x:y;}
int GET_POINT()
{
if(Top) return st[Top--];
return ++tot;
}
void pus(int k)
{
s[k].siz=s[tl].siz+s[tr].siz+1,s[k].mx[0]=s[k].mi[0]=s[k].d[0],s[k].mx[1]=s[k].mi[1]=s[k].d[1];
if(tl) s[k].mx[0]=max(s[k].mx[0],s[tl].mx[0]),s[k].mi[0]=min(s[k].mi[0],s[tl].mi[0]),s[k].mx[1]=max(s[k].mx[1],s[tl].mx[1]),s[k].mi[1]=min(s[k].mi[1],s[tl].mi[1]);
if(tr) s[k].mx[0]=max(s[k].mx[0],s[tr].mx[0]),s[k].mi[0]=min(s[k].mi[0],s[tr].mi[0]),s[k].mx[1]=max(s[k].mx[1],s[tr].mx[1]),s[k].mi[1]=min(s[k].mi[1],s[tr].mi[1]);
}
int build(int l=1,int r=n,bool d=0)
{
if(l>r) return 0;
int k=GET_POINT();
return D=d,nth_element(s1+l,s1+mid,s1+1+r),s[k]=s1[mid],s[k].siz=1,tl=build(l,mid-1,d^1),tr=build(mid+1,r,d^1),pus(k),k;
}
void dfs(int k,int siz=1)
{
if(tl) dfs(tl,siz);
s1[siz+s[tl].siz]=s[k],st[++Top]=k;
if(tr) dfs(tr,siz+s[tl].siz+1);
}
void look(int &k,bool D) {if(double(s[tl].siz)>aph*s[k].siz||double(s[tr].siz)>aph*s[k].siz) dfs(k),k=build(1,s[k].siz,D);}
void add(int &k,int x,bool D=0)
{
if(!k) return void(k=x);
if(s[x].d[D]<=s[k].d[D]) add(tl,x,D^1);
else add(tr,x,D^1);
pus(k),look(k,D);
}
int ask(int x,int y,int _x,int _y,int k)
{
if(!k) return 0;
if(x<=s[k].mi[0]&&y<=s[k].mi[1]&&_x>=s[k].mx[0]&&_y>=s[k].mx[1]) return s[k].siz;
if(x>s[k].mx[0]||_x<s[k].mi[0]||y>s[k].mx[1]||_y<s[k].mi[1]) return 0;
return (x<=s[k].d[0]&&y<=s[k].d[1]&&_x>=s[k].d[0]&&_y>=s[k].d[1])+ask(x,y,_x,_y,tl)+ask(x,y,_x,_y,tr);
}
int read()
{
int x(0);
char ch=getchar();
for(;!isdigit(ch);ch=getchar());
for(;isdigit(ch);x=x*10+ch-48,ch=getchar());
return x;
}
int main()
{
n=read(),Q=read();
for(int i=1,x,_x,y;i<=n;++i)
_x=i,a[i]=y=read(),x=_x+y,y=_x-y,s1[i].add(x,y);
rt=build();
for(int i=1,x,y,_x,_y,k;i<=Q;++i)
{
scanf("%s",A),_x=read(),_y=y=read();
if(A[0]=='Q') y=a[_x],x=_x+y,y=_x-y,printf("%d\n",ask(x-_y,y-_y,x+_y,y+_y,rt));
else if(A[0]=='M') a[_x]=y,x=_x+y,y=_x-y,k=GET_POINT(),s[k].add(x,y),add(rt,k);
}
return 0;
}