发现进位或退位时,会有连续的一段1变成0或连续的0变成1,然后在后面产生一个进位或退位。于是我们只需要一颗线段树支持区间赋值,查询左边第一个1/0,以及单点查询值。可以把a按二进制拆开去修改,复杂度是O(nlognloga)的,这样好像过不去。
于是我的做法是在线段树的每个叶子节点存30位,用一个int保存,修改时就只需将a拆成跨过叶子节点的两部分,每部分直接加到对应的叶子节点,若超过了$2^{30}-1$就往前进一位即可(减法的话就看减去以后有没有小于0,有就向前借一位),复杂度O(nlogn)。
查询左边第一个0/1时,可以维护每个区间是全为1/全为0/又有0又有1。
UPD: WC上机练习时重新打了一遍代码,原来的代码又丑又慢。
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> #include<cmath> #include<vector> #define Pputs("lala") #define cpcerr<<"lala"<<endl #define fi first #define se second #define lnputchar(' ') #define pbpush_back using namespace std; inline int read() { char ch=getchar(); int g=1,re=0; while(ch<'0'||ch>'9') {if(ch=='-')g=-1;ch=getchar();} while(ch<='9'&&ch>='0') re=(re<<1)+(re<<3)+(ch^48),ch=getchar(); return re*g; } typedef long long ll; typedef pair<int,int>pii; typedef unsigned int ui; const int N=1005000; int all[2]={0,(1<<30)-1}; const int both=85490; int n,sum[N<<2],setv[N<<2]; void pushdown(int o) { if(setv[o]!=-1) { setv[o<<1]=setv[o]; setv[o<<1|1]=setv[o]; sum[o<<1]=all[setv[o]]; sum[o<<1|1]=all[setv[o]]; setv[o]=-1; } } int jin=0,found=0,ret=-1; namespace add { void update(int o,int l,int r,int b,int x) { if(l==r) { sum[o]+=x; if(sum[o]>all[1]) sum[o]&=all[1],jin=1; return ; } pushdown(o); int mid=l+r>>1; if(b<=mid) update(o<<1,l,mid,b,x); else update(o<<1|1,mid+1,r,b,x); if(sum[o<<1]==sum[o<<1|1]&&(sum[o<<1]==all[0]||sum[o<<1]==all[1])) sum[o]=sum[o<<1]; else sum[o]=both; } void gonex(int o,int l,int r) { if(l==r) { ret=l-1; for(int i=0;i<30;++i) if(sum[o]&1<<i) sum[o]^=1<<i; else {sum[o]^=1<<i;break;} return ; } pushdown(o); int mid=l+r>>1; if(sum[o<<1]!=all[1]) gonex(o<<1,l,mid); else gonex(o<<1|1,mid+1,r); if(sum[o<<1]==sum[o<<1|1]&&(sum[o<<1]==all[0]||sum[o<<1]==all[1])) sum[o]=sum[o<<1]; else sum[o]=both; } void findnex(int o,int l,int r,int x,int y) { if(found) return ; if(x<=l&&r<=y) { if(sum[o]!=all[1]) found=1,gonex(o,l,r); return ; } pushdown(o); int mid=l+r>>1; if(x<=mid) findnex(o<<1,l,mid,x,y); if(y>mid) findnex(o<<1|1,mid+1,r,x,y); if(sum[o<<1]==sum[o<<1|1]&&(sum[o<<1]==all[0]||sum[o<<1]==all[1])) sum[o]=sum[o<<1]; else sum[o]=both; } void modify(int o,int l,int r,int x,int y) { if(x<=l&&r<=y) {setv[o]=0;sum[o]=all[0];return ;} pushdown(o); int mid=l+r>>1; if(x<=mid) modify(o<<1,l,mid,x,y); if(y>mid) modify(o<<1|1,mid+1,r,x,y); if(sum[o<<1]==sum[o<<1|1]&&(sum[o<<1]==all[0]||sum[o<<1]==all[1])) sum[o]=sum[o<<1]; else sum[o]=both; } } namespace sub { void update(int o,int l,int r,int b,int x) { if(l==r) { sum[o]-=x; if(sum[o]<0) sum[o]+=all[1]+1,jin=1; return ; } pushdown(o); int mid=l+r>>1; if(b<=mid) update(o<<1,l,mid,b,x); else update(o<<1|1,mid+1,r,b,x); if(sum[o<<1]==sum[o<<1|1]&&(sum[o<<1]==all[0]||sum[o<<1]==all[1])) sum[o]=sum[o<<1]; else sum[o]=both; } void gonex(int o,int l,int r) { if(l==r) { ret=l-1; for(int i=0;i<30;++i) if(!(sum[o]&1<<i)) sum[o]^=1<<i; else {sum[o]^=1<<i;break;} return ; } pushdown(o); int mid=l+r>>1; if(sum[o<<1]!=all[0]) gonex(o<<1,l,mid); else gonex(o<<1|1,mid+1,r); if(sum[o<<1]==sum[o<<1|1]&&(sum[o<<1]==all[0]||sum[o<<1]==all[1])) sum[o]=sum[o<<1]; else sum[o]=both; } void findnex(int o,int l,int r,int x,int y) { if(found) return ; if(x<=l&&r<=y) { if(sum[o]!=all[0]) found=1,gonex(o,l,r); return ; } pushdown(o); int mid=l+r>>1; if(x<=mid) findnex(o<<1,l,mid,x,y); if(y>mid) findnex(o<<1|1,mid+1,r,x,y); if(sum[o<<1]==sum[o<<1|1]&&(sum[o<<1]==all[0]||sum[o<<1]==all[1])) sum[o]=sum[o<<1]; else sum[o]=both; } void modify(int o,int l,int r,int x,int y) { if(x<=l&&r<=y) {setv[o]=1;sum[o]=all[1];return ;} pushdown(o); int mid=l+r>>1; if(x<=mid) modify(o<<1,l,mid,x,y); if(y>mid) modify(o<<1|1,mid+1,r,x,y); if(sum[o<<1]==sum[o<<1|1]&&(sum[o<<1]==all[0]||sum[o<<1]==all[1])) sum[o]=sum[o<<1]; else sum[o]=both; } } int query(int o,int l,int r,int k) { if(l==r) return sum[o]>>(k%30)&1; pushdown(o); int mid=l+r>>1; if(k/30<=mid) return query(o<<1,l,mid,k); else return query(o<<1|1,mid+1,r,k); } void wj() { freopen("integer.in","r",stdin); freopen("integer.out","w",stdout); } int main() { //wj(); memset(setv,-1,sizeof(setv)); n=read(); read(); read(); read(); for(int cas=1;cas<=n;++cas) { int opt=read(); if(opt==1) { int a=read(),b=read(); if(!a) continue; if(a>0) { jin=0; ret=-1; found=0; add::update(1,0,n,b/30,(a<<(b%30))&all[1]); if(jin&&b/30<n) add::findnex(1,0,n,b/30+1,n); if(b/30+1<=ret) add::modify(1,0,n,b/30+1,ret); if(!(a>>(30-b%30))) continue; jin=0; ret=-1; found=0; add::update(1,0,n,b/30+1,a>>(30-b%30)); if(jin&&b/30+1<n) add::findnex(1,0,n,b/30+2,n); if(b/30+2<=ret) add::modify(1,0,n,b/30+2,ret); } else { a=-a; jin=0; ret=-1; found=0; sub::update(1,0,n,b/30,(a<<(b%30))&all[1]); if(jin&&b/30<n) sub::findnex(1,0,n,b/30+1,n); if(b/30+1<=ret) sub::modify(1,0,n,b/30+1,ret); if(!(a>>(30-b%30))) continue; jin=0; ret=-1; found=0; sub::update(1,0,n,b/30+1,a>>(30-b%30)); if(jin&&b/30+1<n) sub::findnex(1,0,n,b/30+2,n); if(b/30+2<=ret) sub::modify(1,0,n,b/30+2,ret); } } else { int k=read(); printf("%d ",query(1,0,n,k)); } } return 0; }