暴力就是真正的暴力,直接手動模擬進位就行了。
此時複雜度是模擬的複雜度加上單次詢問的\(O(1)\)。
因此咱們須要優化的是模擬的複雜度。
首先若是一位位單位加入,這個複雜度是均攤\(O(1)\)的。由於是均攤,因此咱們不能支持撤銷(即減法操做),因此加法減法必須分開處理。
對於位運算加法咱們考慮壓位(或者說分塊也是同樣的啦)
那麼加法就很容易處理了,只須要壓位以後找到對應的塊,而後直接暴力加上去就好了。
這裏稍微注意一下進位的細節。
減法相似處理。
那麼最後這樣子又變的很差查詢了。
而查詢的方法就是考慮這一位要不要退位。
退位的話就是加法的和減去減法的和,等價於比較兩個後綴大小,比較兩個後綴大小能夠用\(set\)維護哪些塊不相同,徹底相同的沒有必要比,只須要找到第一個不一樣的塊的就好了。
寫法上的話,看到洛谷題解裏用\(unsigned\ int\)壓\(32\)位,這樣子就不須要本身手動取模了,挺方便的。ios
#include<iostream> #include<cstdio> #include<set> using namespace std; #define ui unsigned int #define MAX 1000100 inline int read() { int x=0;bool t=false;char ch=getchar(); while((ch<'0'||ch>'9')&&ch!='-')ch=getchar(); if(ch=='-')t=true,ch=getchar(); while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar(); return t?-x:x; } ui A[MAX],B[MAX]; int n; set<int> S; int main() { n=read();read();read();read(); while(n--) { int opt=read(); if(opt==1) { int a=read(),b=read(); int p=b/32,r=b%32; if(a>0) { ui s0=(ui)a<<r,s1=r?((ui)a>>(32-r)):0; ui lst=A[p];A[p]+=s0;s1+=(lst>A[p]); if(A[p]^B[p])S.insert(p); else if(S.find(p)!=S.end())S.erase(p); ++p; while(s1) { lst=A[p];A[p]+=s1;s1=(lst>A[p]); if(A[p]^B[p])S.insert(p); else if(S.find(p)!=S.end())S.erase(p); ++p; } } else { a=-a; ui s0=(ui)a<<r,s1=r?((ui)a>>(32-r)):0; ui lst=B[p];B[p]+=s0;s1+=(lst>B[p]); if(A[p]^B[p])S.insert(p); else if(S.find(p)!=S.end())S.erase(p); ++p; while(s1) { lst=B[p];B[p]+=s1;s1=(lst>B[p]); if(A[p]^B[p])S.insert(p); else if(S.find(p)!=S.end())S.erase(p); ++p; } } } else { int a=read(); int p=a/32,r=a%32; int ans=((A[p]>>r)&1)^((B[p]>>r)&1); ui va=A[p]&((1<<r)-1),vb=B[p]&((1<<r)-1); if(va<vb)ans^=1; else if(va>vb||S.empty()||p<=*S.begin()); else { set<int>::iterator it=S.lower_bound(p);--it; if(A[*it]<B[*it])ans^=1; } printf("%d\n",ans); } } return 0; }