【noi2017】 整數 線段樹or模擬

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 }
相關文章
相關標籤/搜索