题目:https://loj.ac/problem/2302
压30位,a最多落在两个位置上,拆成两次操作。
该位置加了 a 之后,如果要进位或者借位,查询一下连续一段 0 / 1 ,修改掉,再在含有 1 / 0 的那个位置上 -1 或者 +1 。
注意是在那个位置上 -1 或者 +1 而不是 -lowbit 或者 +lowbit 。
询问都是 <=30n ,所以只维护 30n 的范围即可。注意线段树压 30 位,开 n 个位置恰好是 0*n ~ 29*n,所以开 n+1 个位置。
线段树只需维护自己区间是全 0 / 1 还是都有。找连续一段 0/1 就在线段树上二分即可。
#include<cstdio> #include<cstring> #include<algorithm> #define ls Ls[cr] #define rs Rs[cr] using namespace std; int rdn() { int ret=0;bool fx=1;char ch=getchar(); while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();} while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar(); return fx?ret:-ret; } int Mx(int a,int b){return a>b?a:b;} int Mn(int a,int b){return a<b?a:b;} const int N=2e6+5,bs=30; int n,nr,tot,Ls[N],Rs[N],lx[N],vl[N],tg[N]; int bin[bs+5],U; bool fx; void build(int l,int r,int cr) { tg[cr]=-1; lx[cr]=vl[cr]=0; if(l==r)return; int mid=l+r>>1; ls=++tot; build(l,mid,ls); rs=++tot; build(mid+1,r,rs); } void pshd(int cr) { if(tg[cr]==-1)return; int k=tg[cr]; tg[cr]=-1; tg[ls]=tg[rs]=k; if(k==1){ vl[ls]=vl[rs]=U; lx[ls]=lx[rs]=1;} else { vl[ls]=vl[rs]=0; lx[ls]=lx[rs]=0;} } void pshp(int cr) { if((!lx[ls])&&(!lx[rs]))lx[cr]=0; else if(lx[ls]==1&&lx[rs]==1)lx[cr]=1; else lx[cr]=2; } void updt(int cr) { if(!vl[cr])lx[cr]=0; else if(vl[cr]==U)lx[cr]=1; else lx[cr]=2;} int fnd(int l,int r,int cr,int L,int R,int k) { if(l>=L&&r<=R) { if(lx[cr]==(!k))return nr+1; if(l==r)return l; int mid=l+r>>1; pshd(cr); if(lx[ls]!=(!k))return fnd(l,mid,ls,L,R,k); return fnd(mid+1,r,rs,L,R,k); } int mid=l+r>>1,d=nr+1; pshd(cr); if(L<=mid)d=fnd(l,mid,ls,L,R,k); if(d==nr+1)d=fnd(mid+1,r,rs,L,R,k); return d; } void mdfy(int l,int r,int cr,int L,int R,int k) { if(l>=L&&r<=R) { tg[cr]=k; if(k==1){vl[cr]=U;lx[cr]=1;} else {vl[cr]=0;lx[cr]=0;} return; } int mid=l+r>>1; pshd(cr); if(L<=mid)mdfy(l,mid,ls,L,R,k); if(mid<R)mdfy(mid+1,r,rs,L,R,k); pshp(cr); } void mdfy2(int l,int r,int cr,int p,int k) { if(l==r) { if(k==1)vl[cr]++; else vl[cr]--;///// /*if(k==1){ int tmp=(vl[cr]^U); vl[cr]+=(tmp&(-tmp));} else vl[cr]-=(vl[cr]&(-vl[cr]));*/ updt(cr); return; } int mid=l+r>>1; pshd(cr); if(p<=mid)mdfy2(l,mid,ls,p,k); else mdfy2(mid+1,r,rs,p,k); pshp(cr); } void add(int p) { int d=fnd(1,nr,1,p,nr,0);//fnd first 0 if(p<d)mdfy(1,nr,1,p,d-1,0); if(d<=nr)mdfy2(1,nr,1,d,1);//chg 0 to 1 } void dec(int p) { int d=fnd(1,nr,1,p,nr,1); if(p<d)mdfy(1,nr,1,p,d-1,1); if(d<=nr)mdfy2(1,nr,1,d,0); } void solve(int l,int r,int cr,int p,int k) { if(l==r) { if(!fx)vl[cr]+=k; else vl[cr]-=k; if(vl[cr]>=bin[bs]){ vl[cr]-=bin[bs];add(l+1);} if(vl[cr]<0){ vl[cr]+=bin[bs];dec(l+1);} updt(cr); return; } int mid=l+r>>1; pshd(cr); if(p<=mid)solve(l,mid,ls,p,k); else solve(mid+1,r,rs,p,k); pshp(cr); } bool qry(int l,int r,int cr,int p,int p2) { if(l==r)return vl[cr]&bin[p2]; int mid=l+r>>1; pshd(cr); if(p<=mid)return qry(l,mid,ls,p,p2); else return qry(mid+1,r,rs,p,p2); } int main() { n=rdn(); nr=n+1; int tp=rdn();tp=rdn();tp=rdn(); bin[0]=1;for(int i=1;i<=bs;i++)bin[i]=bin[i-1]<<1; U=bin[bs]-1; tot=1;build(1,nr,1); for(int i=1,op,a,b,l,r;i<=n;i++) { op=rdn(); if(op==1) { a=rdn();b=rdn(); l=b; r=b+bs-1; l=l/bs+1; r=r/bs+1; if(a<0)a=-a,fx=1; else fx=0; if(l<r) { int k=a&(bin[l*bs-b]-1); a>>=(l*bs-b); k<<=(b-(l-1)*bs); solve(1,nr,1,l,k); solve(1,nr,1,r,a); } else solve(1,nr,1,l,a); } else { a=rdn(); l=a/bs+1; a-=(l-1)*bs; printf("%d ",qry(1,nr,1,l,a)); } } return 0; }