首先把每32位压成一个unsigned int(当然只要压起来能过就行)。如果不考虑进/退位的话,每次只要将加/减上去的数拆成两部分直接单点修改就好了。那么考虑如何维护进/退位。可以发现进位的过程其实就是将一段连续的inf改为0,并把之后一位+1,也就是说只要找到某一位之后第一个不是inf的位就好了。我们用线段树维护这个东西,记录一下某个节点表示的区间是否全为inf。查询时先从叶子节点往上爬,直到当前节点代表的区间中在该叶子节点右边的位不全为inf时停止,之后再往下找最左的非inf位。退位类似。这样的话复杂度就是O(nlogn)。
写起来挺烦的,注意一下各种细节,码力极弱选手表示调了快一天……惨惨。
// luogu-judger-enable-o2 #include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } #define N 1000010 #define ui unsigned int #define inf 4294967295 #define lson (k<<1) #define rson (k<<1|1) #define getmid; int mid=tree[k].l+tree[k].r>>1; int n; struct data{int l,r,tag,size,sumzero,suminf;ui num; }tree[N<<2]; bool isleaf(int k){return tree[k].size==1;} void build(int k,int l,int r) { tree[k].l=l,tree[k].r=r,tree[k].size=r-l+1; tree[k].sumzero=tree[k].size,tree[k].suminf=0; if (isleaf(k)) return; getmid; build(lson,l,mid); build(rson,mid+1,r); } void up(int k) { tree[k].sumzero=tree[lson].sumzero+tree[rson].sumzero; tree[k].suminf=tree[lson].suminf+tree[rson].suminf; } void update(int k,int tag) { if (tag>0) tree[k].sumzero=tree[k].size,tree[k].suminf=0; else tree[k].sumzero=0,tree[k].suminf=tree[k].size; tree[k].tag=tag; if (isleaf(k)) tree[k].num=tag>0?0:inf; } void down(int k) { if (tree[k].tag) { update(lson,tree[k].tag); update(rson,tree[k].tag); tree[k].tag=0; } } int find(int k,int x) { if (isleaf(k)) return k; down(k); getmid; int ans; if (x<=mid) ans=find(lson,x); else ans=find(rson,x); up(k); return ans; } void modify(int k,int l,int r,int tag) { if (tree[k].l==l&&tree[k].r==r) { update(k,tag); return; } down(k); getmid; if (r<=mid) modify(lson,l,r,tag); else if (l>mid) modify(rson,l,r,tag); else modify(lson,l,mid,tag),modify(rson,mid+1,r,tag); up(k); } int add(int k,int p,ui x) { if (isleaf(k)) { int v=inf-tree[k].num<x; tree[k].num+=x; tree[k].sumzero=(tree[k].num==0); tree[k].suminf=(tree[k].num==inf); return v; } down(k); getmid; int ans; if (p<=mid) ans=add(lson,p,x); else ans=add(rson,p,x); up(k); return ans; } int dec(int k,int p,ui x) { if (isleaf(k)) { int v=tree[k].num<x; tree[k].num-=x; tree[k].sumzero=(tree[k].num==0); tree[k].suminf=(tree[k].num==inf); return v; } down(k); getmid; int ans; if (p<=mid) ans=dec(lson,p,x); else ans=dec(rson,p,x); up(k); return ans; } void pushup(int k) { if (tree[k].suminf) { int t=k,cnt=0; while (tree[k].suminf-cnt==tree[k].r-tree[t].l+1) { if (k&1) cnt+=tree[k-1].suminf; k>>=1; } k=rson; while (!isleaf(k)) { down(k); if (tree[lson].suminf==tree[lson].size) k=rson; else k=lson; } modify(1,tree[t].l,tree[k].l-1,1); } add(1,tree[k].l,1); } void pushdown(int k) { if (tree[k].sumzero) { int t=k,cnt=0; while (tree[k].sumzero-cnt==tree[k].r-tree[t].l+1) { if (k&1) cnt+=tree[k-1].sumzero; k>>=1; } k=rson; while (!isleaf(k)) { down(k); if (tree[lson].sumzero==tree[lson].size) k=rson; else k=lson; } modify(1,tree[t].l,tree[k].l-1,-1); } dec(1,tree[k].l,1); } int query(int k,int p,int x) { if (isleaf(k)) return tree[k].num>>x&1; down(k); getmid; int ans; if (p<=mid) ans=query(lson,p,x); else ans=query(rson,p,x); up(k); return ans; } int main() { n=read();read(),read(),read(); build(1,1,n+2); for (int i=1;i<=n;i++) { int op=read(); if (op==1) { int x=read(),y=read(); if (x>0) { ui v=x; ui a=v<<(y&31),b=(y&31)?(v>>(32-(y&31))):0; if (a>0) b+=add(1,(y>>5)+1,a); if (b>0) { a=add(1,(y>>5)+2,b); if (a>0) pushup(find(1,(y>>5)+3)); } } else { ui v=abs(x); ui a=v<<(y&31),b=(y&31)?(v>>(32-(y&31))):0; if (a>0) b+=dec(1,(y>>5)+1,a); if (b>0) { a=dec(1,(y>>5)+2,b); if (a>0) pushdown(find(1,(y>>5)+3)); } } } else { int x=read(); printf("%d ",query(1,(x>>5)+1,x&31)); } } return 0; }