版权声明:欢迎转载(请附带原链接)ヾ(๑╹◡╹)ノ" https://blog.csdn.net/corsica6/article/details/84931074
传送门:bzoj2989
题解
欧几里得距离转成曼哈顿距离 之后问题就变成了每次给一个点+1,询问某个矩形范围内的总值。
通常方法是 ,二进制分组可以解决强制在线的限制。
具体来说,设现有总操作数为 , 转成2进制后有 位,则将操作分成按 的二进制来划分:对于任意 若 ,则划分出一个大小为 的组(实际操作很简单,没有我说的复杂。。。)。
对于每个询问就在这 个组中依次查询。主席树替代了二维线段树的功能, 这一维维护递增的 坐标,树内维护递增的值域范围内的 坐标。所以每次二分找出 坐标对应的树范围,查询区间 的总值即可。
对于每个新增的操作,强行划分出一个大小为1的组后不断向前合并即可。
复杂度 。需要建内存池动态维护线段树的点标号。
代码
#include<bits/stdc++.h>
#define mid ((l+r)>>1)
#define lc ls[k],l,mid
#define rc rs[k],mid+1,r
#define pb push_back
using namespace std;
const int N=6e4+10,M=1e5+10,MX=16e4,NX=1e7+5;
int n,m,cnt,a[N],rt[20][M],num,top;
int ss[NX],ls[NX],rs[NX];
char op[10];bool vs[NX];
struct Pl{
int que[NX],top;
inline int pop(){int re;if(!top) re=++cnt;else re=que[top--];vs[re]=true;return re;}
inline void psh(int x){que[++top]=x;vs[x]=false;ls[x]=rs[x]=ss[x]=0;}
}pl;
struct Pr{
int x,y;
Pr(int x_=0,int y_=0):x(x_),y(y_){};
bool operator <(const Pr&ky) const{return x==ky.x?y<ky.y:x<ky.x;}
bool operator ==(const Pr&ky) const{return (x==ky.x && y==ky.y);}
}rep[M];
vector<Pr>v[20];
void ins(int pre,int &k,int l,int r,int pos)
{
k=pl.pop();ss[k]=ss[pre]+1;ls[k]=ls[pre],rs[k]=rs[pre];
if(l^r){if(pos<=mid) ins(ls[pre],lc,pos);else ins(rs[pre],rc,pos);}
}
void dl(int k,int l,int r)
{if((!vs[k])) return;if(l^r) dl(lc),dl(rc);pl.psh(k);}
inline void ins(int x,int y)
{
int i,j,len;
v[++num].pb(Pr(x,y));
ins(rt[num][0],rt[num][1],1,MX,y);
for(;num>1 && v[num].size()==v[num-1].size();){
len=v[num].size();top=0;
for(i=1;i<=len;++i) dl(rt[num][i],1,MX),dl(rt[num-1][i],1,MX);
i=j=0;
for(;i<len || j<len;){
if((j>=len) || (i<len && v[num-1][i]<v[num][j])){
ins(rt[num-1][i+j],rt[num-1][i+j+1],1,MX,v[num-1][i].y);
rep[top++]=v[num-1][i++];
}else{
ins(rt[num-1][i+j],rt[num-1][i+j+1],1,MX,v[num][j].y);
rep[top++]=v[num][j++];
}
}
v[num--].clear();v[num].clear();
for(i=0;i<top;++i) v[num].pb(rep[i]);
}
}
int ask(int pre,int k,int l,int r,int L,int R)
{
if(ss[k]==ss[pre]) return 0;
if(L<=l && r<=R) return ss[k]-ss[pre];
if(R<=mid) return ask(ls[pre],lc,L,R);
if(L>mid) return ask(rs[pre],rc,L,R);
return ask(ls[pre],lc,L,R)+ask(rs[pre],rc,L,R);
}
inline int query(int x,int y,int vv)
{
int i,re=0,a,b,l=max(1,y-vv),r=min(MX,y+vv);
for(i=1;i<=num;++i){
a=lower_bound(v[i].begin(),v[i].end(),Pr(x-vv,0))-v[i].begin();
b=lower_bound(v[i].begin(),v[i].end(),Pr(x+vv,2e9))-v[i].begin();
re+=ask(rt[i][a],rt[i][b],1,MX,l,r);
}
printf("%d\n",re);
}
int main(){
int i,x,y;
scanf("%d%d",&n,&m);
for(i=1;i<=n;++i) {scanf("%d",&a[i]);ins(a[i]+i,a[i]-i+N);}
for(;m;--m){
scanf("%s%d%d",op,&x,&y);
if(op[0]=='Q') query(a[x]+x,a[x]-x+N,y);
else a[x]=y,ins(y+x,y-x+N);
}
return 0;
}