ORZYYBc++
題目大意:你須要維護一個有$3\times 10^7$個二進制位的數,有一種修改方式和一種詢問方式spa
對這個數加上$a\times2^b$,其中$|a|≤10^9$,$b≤3\times 10^7$,保證須要維護的這個數始終非負code
詢問這個數第k個二進制位的值blog
總共有$10^6$次詢問/修改操做it
咱們不難發現,若是隻有加法操做的話,對任意一個位執行加法操做,均攤進位次數是1。class
證實是顯然的(我貌似以前在MC裏面用紅石電路模擬過二進制進位過程。。。。)二進制
也就是說暴力加暴力進位的複雜度是正確的。im
可是這裏有a並不保證非負,這樣一來經過精心(大霧)的構造方式,可讓你瘋狂進位/退位,因此並不能單純暴力模擬。查詢
咱們考慮對加法部分和減法部分分開維護(設A爲加法的部分,B爲減法的部分),這樣的進位複雜度顯然就是對的。di
考慮到$A≥B$,那麼顯然有$\frac{A}{2^k}≥\frac{B}{2^k}$。
對於每次查詢操做,咱們分別找出A的第k位和B的第k位
如今對答案會產生影響的顯然是A的末k-1位和B的末k-1位相減後,A的第k位是否須要退位。
咱們考慮開一個set,若A的第i位和B的第i位不一樣,那麼咱們就把i丟入set中。
咱們考慮在set中找到知足<k的i,直接判斷A的第i位和B的第i位的大小關係,就能夠判出是否會產生退位。
set的維護在對大數作修改的時候去更新。
考慮到這個數很是大,直接維護會超時,咱們不妨作一波壓位,而後再來維護,這樣就跑得快不少了。
注意!對於一個32位的數,左移32位的操做會直接被忽略。
固然以前還有一些比較菜的想法,維護整個數的差分序列,若差分序列某個位置不爲0就丟入set中,而後也來壓位一波,不過代碼估計長不少。
時間複雜度:$O(n\ log\ n)$
1 #include<bits/stdc++.h> 2 #define M 500005 3 #define S 64 4 #define L unsigned long long 5 using namespace std; 6 7 int n,t1,t2,t3; 8 L a[M]={0},b[M]={0},P=-1; 9 set<int> s; 10 11 void upd(int x){ 12 if(a[x]!=b[x]) s.insert(x); 13 else{ 14 if(s.find(x)!=s.end()) s.erase(x); 15 } 16 } 17 18 int main(){ 19 scanf("%d%d%d%d",&n,&t1,&t2,&t3); 20 while(n--){ 21 int op,B; scanf("%d",&op); L A; 22 int aa; 23 if(op==1){ 24 scanf("%d%d",&aa,&B); 25 if(aa>0){ 26 A=aa; 27 int x=B/S,y=B%S; 28 L s1=(A<<y)&P,s2=y?(A>>(S-y)):0; 29 a[x]=a[x]+s1; upd(x); 30 if(a[x]<s1) s2++; 31 while(s2){ 32 x++; 33 a[x]=a[x]+s2; upd(x); 34 s2=(a[x]<s2); 35 } 36 }else{ 37 A=-aa; 38 int x=B/S,y=B%S; 39 L s1=(A<<y)&P,s2=y?(A>>(S-y)):0; 40 b[x]=b[x]+s1; upd(x); 41 if(b[x]<s1) s2++; 42 while(s2){ 43 x++; 44 b[x]=b[x]+s2; upd(x); 45 s2=(b[x]<s2); 46 } 47 } 48 }else{ 49 scanf("%d",&B); 50 int x=B/S,y=B%S; 51 int ans=(((a[x]>>y)^(b[x]>>y))&1); 52 A=y?(a[x]<<(S-y)):0; 53 L BB=y?(b[x]<<(S-y)):0; 54 if(A<BB) ans^=1; 55 if(A==BB){ 56 set<int>::iterator it=s.lower_bound(x); 57 if(it!=s.begin()){ 58 it--; x=*it; 59 if(a[x]<b[x]) ans^=1; 60 } 61 } 62 printf("%d\n",ans); 63 } 64 } 65 }