原题链接:https://www.lydsy.com/JudgeOnline/problem.php?id=4170
极光
Description
“若是万一琪露诺(俗称rhl)进行攻击,什么都好,冷静地回答她的问题来吸引她。对方表现出兴趣的话,那就慢慢地反问。在她考虑答案的时候,趁机逃吧。就算是很简单的问题,她一定也答不上来。” –《上古之魔书》
天空中出现了许多的北极光,这些北极光组成了一个长度为n的正整数数列a[i],远古之魔书上记载到:2个位置的graze值为两者位置差与数值差的和:
graze(x,y)=|x-y|+|a[x]-a[y]|。
要想破解天罚,就必须支持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
题解
跟BZOJ2989一模一样。。。纯属水博客。
代码
#include<bits/stdc++.h>
#define up(x) MX=max(MX,x)
using namespace std;
const int M=1e6;
struct sd{int op,x,y,val,id,t;};
bool operator <(sd a,sd b)
{
if(a.x!=b.x)return a.x<b.x;
if(a.y!=b.y)return a.y<b.y;
return a.op<b.op;
}
sd ope[M],tmp[M];
int n,q,que[M],ans[M],sum[M],MX,tot,base=1;
bool vis[M];
void off(int op,int id,int x,int y,int k)
{
int xx=x-y,yy=x+y,x1,x2,y1,y2;
if(!op){up(xx),up(yy),ope[++tot]=(sd){op,xx,yy,0,id,tot};}
else
{
x1=xx-k,y1=yy-k,x2=xx+k,y2=yy+k;
if(y1>0)ope[++tot]=(sd){op,x1-1,y1-1,1,id,tot};
ope[++tot]=(sd){op,x1-1,y2,-1,id,tot};
if(y1>0)ope[++tot]=(sd){op,x2,y1-1,-1,id,tot};
ope[++tot]=(sd){op,x2,y2,1,id,tot};
up(x2),up(y2);
}
}
void in()
{
char ch[10];
int a,b;
scanf("%d%d",&n,&q);
for(int i=1;i<=n;++i)scanf("%d",&que[i]),off(0,i,i,que[i],0);
for(int i=n+1;i<=n+q;++i)
{
scanf("%s%d%d",ch,&a,&b);
if(ch[0]=='M'){que[a]=b;off(0,i,a,b,0);}
else off(1,i,a,que[a],b),vis[i]=1;
}
}
void add(int v,int s){v+=base;for(;v;v>>=1)sum[v]+=s;}
int query(int ri)
{
int ans=0,le=base;ri+=base+1;
for(;le^ri^1;le>>=1,ri>>=1)
{
if(le&1^1)ans+=sum[le+1];
if(ri&1)ans+=sum[ri-1];
}
return ans;
}
void cdq(int le,int ri)
{
if(le==ri)return;
int mid=le+ri>>1,p1=le,p2=mid+1;
for(int i=le;i<=ri;++i)
{
if(!ope[i].op&&ope[i].t<=mid)add(ope[i].y,1);
if(ope[i].op&&ope[i].t>mid)ans[ope[i].id]+=ope[i].val*query(ope[i].y);
}
for(int i=le;i<=ri;++i)if(!ope[i].op&&ope[i].t<=mid)add(ope[i].y,-1);
for(int i=le;i<=ri;++i)
if(ope[i].t<=mid)tmp[p1++]=ope[i];
else tmp[p2++]=ope[i];
for(int i=le;i<=ri;++i)ope[i]=tmp[i];
cdq(le,mid);cdq(mid+1,ri);
}
void ac()
{
MX++;while(base<MX)base<<=1;
sort(ope+1,ope+1+tot);cdq(1,tot);
for(int i=1;i<=q+n;++i)if(vis[i])printf("%d\n",ans[i]);
}
int main()
{
in();ac();
return 0;
}