BZOJ2989 数列(二进制分组)
这题其实可以cdq分治做,但是如果强制在线的话,这里有个牛逼方法叫二进制分组。
它的基本思想是把修改操作按二进制分组,遇到修改就在尾部加一个,并与之前的合并,比如之前有23(16+4+2+1)个,加了一个后就变成了24(16+8)个,遇到查询就在每个组内查询,再加起来就好了。
#include <cstdio> #include <vector> #include <algorithm> using namespace std; #define M ((l+r)>>1) #define mk(a,b) make_pair(a,b) typedef pair<int,int> pr; const int N=60005,A=N+100000; char op[9]; int n,q,x,y,tt,tp,a[N],rt[20][100005],rb[10000005],vs[10000005]; vector<pr> v[20]; struct nd {int l,r,s;}t[10000005]; void ins2(int &x,int ls,int l,int r,int v) { t[x=rb[tt--]].s=t[ls].s+1,vs[x]=0; if(l==r) return; if(v<=M) t[x].r=t[ls].r,ins2(t[x].l,t[ls].l,l,M,v); else t[x].l=t[ls].l,ins2(t[x].r,t[ls].r,M+1,r,v); } int qr2(int x,int y,int l,int r,int L,int R) { if(L<=l&&R>=r) return t[x].s-t[y].s; if(R<=M) return qr2(t[x].l,t[y].l,l,M,L,R); if(L>M) return qr2(t[x].r,t[y].r,M+1,r,L,R); return qr2(t[x].l,t[y].l,l,M,L,R)+qr2(t[x].r,t[y].r,M+1,r,L,R); } void dl(int x,int l,int r) { if(vs[x]) return; rb[++tt]=x,vs[x]=1,dl(t[x].l,l,M),dl(t[x].r,M+1,r),t[x].s=t[x].l=t[x].r=0; } void ins(int x,int y) { v[++tp].push_back(mk(x,y)),ins2(rt[tp][1],rt[tp][0],1,A,y); while(tp>1&&v[tp-1].size()==v[tp].size()) { int t1=0,t2=0; vector<pr> t; for(int i=1;i<=v[tp-1].size();i++) dl(rt[tp-1][i],1,A); for(int i=1;i<=v[tp].size();i++) dl(rt[tp][i],1,A); while(t1<v[tp-1].size()||t2<v[tp].size()) { if(t1<v[tp-1].size()&&(t2==v[tp].size()||v[tp-1][t1]<v[tp][t2])) t.push_back(v[tp-1][t1++]),ins2(rt[tp-1][t1+t2],rt[tp-1][t1+t2-1],1,A,v[tp-1][t1-1].second); else t.push_back(v[tp][t2++]),ins2(rt[tp-1][t1+t2],rt[tp-1][t1+t2-1],1,A,v[tp][t2-1].second); } v[tp-1]=t,v[tp].clear(),tp--; } } int qr(int x,int y,int k3) { int r=0; for(int i=1;i<=tp;i++) { int k=lower_bound(v[i].begin(),v[i].end(),mk(x+k3,0x3f3f3f3f))-v[i].begin(); int k2=lower_bound(v[i].begin(),v[i].end(),mk(x-k3,0))-v[i].begin(); r+=qr2(rt[i][k],rt[i][k2],1,A,max(1,y-k3),min(y+k3,A)); } return r; } int main() { scanf("%d%d",&n,&q),vs[0]=1; for(int i=1;i<10000005;i++) rb[++tt]=i,vs[i]=1; for(int i=1;i<=n;i++) scanf("%d",&a[i]),ins(a[i]+i,a[i]-i+N); while(q--) { scanf("%s%d%d",op,&x,&y); if(op[0]=='Q') printf("%d\n",qr(a[x]+x,a[x]-x+N,y)); else a[x]=y,ins(y+x,y-x+N); } return 0; }