题目链接:bzoj4170
题目大意:
天空中出现了许多的北极光,这些北极光组成了一个长度为n的正整数数列a[i],远古之魔书上记载到:2个位置的g
raze值为两者位置差与数值差的和: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的对数。(某位置多次修改为同样的数值,按多次
统计)
题解:
cdq分治+树状数组
把(x,a[x])看成一个点。那么题目要求的就是与某点曼哈顿距离≤k的点的个数。
可以知道与某点距离相等的点可是个菱形,旋转坐标系(x,y)->(x-y,x+y)。于是菱形就转成了正方形。就等于求矩阵内点的个数,差分一下就好了。
时间,x轴,y轴——经典的三维偏序用cdq来做
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define maxn 500010
struct node
{
int x,y,id,mk;
}q[maxn],to[maxn];int cnt,n,lim;
int ans[maxn],a[maxn],c[maxn],lnum,rnum;
int mymax(int x,int y){return (x>y)?x:y;}
int lowbit(int x){return (x&(-x));}
void change(int x,int k) {for (;x<=lim && x!=0;x+=lowbit(x)) c[x]+=k;}
int query(int x){int ret=0;for (;x>0;x-=lowbit(x)) ret+=c[x];return ret;}
void solve(int l,int r)
{
if (l==r) return;
int mid=(l+r)>>1;
solve(l,mid);solve(mid+1,r);
int i,j;
for (i=mid+1,j=l;i<=r;i++)
{
for (;q[j].x<=q[i].x && j<=mid;j++)
if (q[j].mk==0) change(q[j].y,1);
if (q[i].mk) ans[q[i].id]+=q[i].mk*query(q[i].y);
}
for (i=l;i<=mid && q[i].x<=q[r].x;i++) if (q[i].mk==0) change(q[i].y,-1);
int lnum=l,rnum=mid+1;
for (i=l;i<=r;i++)
{
if ((q[lnum].x<=q[rnum].x || rnum>r) && lnum<=mid)
{
to[i]=q[lnum++];
}else to[i]=q[rnum++];
}
for (i=l;i<=r;i++) q[i]=to[i];
}
int main()
{
//freopen("a.in","r",stdin);
//freopen("a.out","w",stdout);
char s[10];int m,i,x,k,tot=0;
scanf("%d%d",&n,&m);cnt=0;
for (i=1;i<=n;i++)
{
scanf("%d",&x);
q[++cnt].x=i-x;q[cnt].y=i+x;
lim=mymax(lim,q[cnt].x);
lim=mymax(lim,q[cnt].y);
q[cnt].mk=0;a[i]=x;
}
for (i=1;i<=m;i++)
{
scanf("%s%d%d",s,&x,&k);
if (s[0]=='M')
{
q[++cnt].x=x-k;q[cnt].y=x+k;q[cnt].mk=0;
a[x]=k;
}else if (s[0]=='Q')
{
q[++cnt].x=x-a[x]+k;q[cnt].y=a[x]+k+x;q[cnt].mk=1;q[cnt].id=++tot;
lim=mymax(lim,q[cnt].x);lim=mymax(lim,q[cnt].y);
q[++cnt].x=x-a[x]-k-1;q[cnt].y=a[x]+x+k;q[cnt].mk=-1;q[cnt].id=tot;
if (a[x]+x-k-1>0) {q[++cnt].x=x-a[x]+k;q[cnt].y=a[x]+x-k-1;q[cnt].mk=-1;q[cnt].id=tot;}
if (a[x]+x-k-1>0) {q[++cnt].x=x-a[x]-k-1;q[cnt].y=a[x]-k+x-1;q[cnt].mk=1;q[cnt].id=tot;}
}
}
memset(ans,0,sizeof(ans));
lim++;solve(1,cnt);
for (i=1;i<=tot;i++) printf("%d\n",ans[i]);
return 0;
}