1. 程式人生 > 其它 >NOIP 模擬23

NOIP 模擬23

T1:

  序列操作,支援區間覆蓋,區間異或,線段樹解決

線段樹區間操作時間複雜度的保證就是懶惰標記,可以說

懶惰標記就是線段樹的核心

  考慮懶惰標記的本質是記錄操作所帶來的影響,僅在

使用時才拓展歷史上所造成的影響,以此保證時間複雜度。

於是,當存在多種影響時(多個標記),須考慮影響之間

的邏輯關係與影響,以一定的關係進行多影響的拓展。

  對於本題而言,兩種思路,一是直接記錄最靠左0的

位置進行拓展,考慮每種操作的影響(操作3是將最左0與

最左1位置互換),發現要拓展出最左1進行輔助轉移。

  二是記錄區間中0的個數,類似與區間求排名的方式

找到最左值即可

  對於懶惰標記的下放,首先區間覆蓋的優先順序大於

區間異或(由標記本身的性質得出),因此,在轉移3標記

時,要先考慮1,2標記的影響。

程式碼如下:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef int I;
 4 typedef void V;
 5 typedef bool B;
 6 typedef long long LL;
 7 const I MAXM = 1e5 + 3;
 8 I m,cnt;
 9 LL auxiliary[MAXM * 3];
10 struct QUERY {
11     I typ;
12     LL l,r;
13 }question[MAXM]; 14 inline V Discretization () { 15 for (I i(1);i <= m; ++ i) 16 auxiliary[++cnt] = question[i].l, auxiliary[++cnt] = question[i].r, auxiliary[++cnt] = question[i].r + 1; 17 sort (auxiliary + 1,auxiliary + cnt + 1); 18 cnt = unique (auxiliary + 1,auxiliary + cnt + 1
) - auxiliary - 1; 19 for (I i(1);i <= m; ++ i) 20 question[i].l = lower_bound (auxiliary + 1,auxiliary + cnt + 1,question[i].l) - auxiliary, 21 question[i].r = lower_bound (auxiliary + 1,auxiliary + cnt + 1,question[i].r) - auxiliary; 22 } 23 namespace SGT { 24 #define lc(x) (x << 1) 25 #define rc(x) (x << 1 | 1) 26 #define mid (l + r >> 1) 27 #define update(x) (pos0[x] = min (pos0[lc(x)],pos0[rc(x)]),pos1[x] = min(pos1[lc(x)],pos1[rc(x)])) 28 I pos0[MAXM * 12],pos1[MAXM * 12]; 29 bool tag1[MAXM * 12],tag2[MAXM * 12],tag3[MAXM * 12]; 30 inline V pushdown (I x,I l,I r) { 31 if (tag1[x]) { 32 tag1[x] = 0; 33 pos0[lc(x)] = INT_MAX, pos1[lc(x)] = l, tag1[lc(x)] = 1, tag2[lc(x)] = tag3[lc(x)] = 0; 34 pos0[rc(x)] = INT_MAX, pos1[rc(x)] = mid + 1, tag1[rc(x)] = 1, tag2[rc(x)] = tag3[rc(x)] = 0; 35 } 36 if (tag2[x]) { 37 tag2[x] = 0; 38 pos0[lc(x)] = l, pos1[lc(x)] = INT_MAX, tag2[lc(x)] = 1, tag1[lc(x)] = tag3[lc(x)] = 0; 39 pos0[rc(x)] = mid + 1, pos1[rc(x)] = INT_MAX, tag2[rc(x)] = 1, tag1[rc(x)] = tag3[rc(x)] = 0; 40 } 41 if (tag3[x]) { 42 tag3[x] = 0; 43 swap (pos0[lc(x)],pos1[lc(x)]), tag1[lc(x)] || tag2[lc(x)] ? (swap (tag1[lc(x)],tag2[lc(x)]),1) : tag3[lc(x)] ^= 1; 44 swap (pos0[rc(x)],pos1[rc(x)]), tag1[rc(x)] || tag2[rc(x)] ? (swap (tag1[rc(x)],tag2[rc(x)]),1) : tag3[rc(x)] ^= 1; 45 } 46 } 47 V found (I x,I l,I r) { 48 pos0[x] = l, pos1[x] = INT_MAX; 49 if (l == r) return ; 50 found (lc(x),l,mid), found (rc(x),mid + 1,r); 51 } 52 V secmod1 (I x,I l,I r,I ql,I qr) { 53 if (ql <= l && r <= qr) return (V)(pos0[x] = INT_MAX, pos1[x] = l, tag1[x] = 1, tag2[x] = tag3[x] = 0); 54 pushdown (x,l,r); 55 if (ql <= mid) secmod1 (lc(x),l,mid,ql,qr); 56 if (qr > mid) secmod1 (rc(x),mid + 1,r,ql,qr); 57 update (x); 58 } 59 V secmod2 (I x,I l,I r,I ql,I qr) { 60 if (ql <= l && r <= qr) return (V)(pos0[x] = l, pos1[x] = INT_MAX, tag2[x] = 1, tag1[x] = tag3[x] = 0); 61 pushdown (x,l,r); 62 if (ql <= mid) secmod2 (lc(x),l,mid,ql,qr); 63 if (qr > mid) secmod2 (rc(x),mid + 1,r,ql,qr); 64 update (x); 65 } 66 V secmod3 (I x,I l,I r,I ql,I qr) { 67 if (ql <= l && r <= qr) return (V)(swap (pos0[x],pos1[x]), tag1[x] || tag2[x] ? (swap (tag1[x],tag2[x]),1) : tag3[x] ^= 1); 68 pushdown (x,l,r); 69 if (ql <= mid) secmod3 (lc(x),l,mid,ql,qr); 70 if (qr > mid) secmod3 (rc(x),mid + 1,r,ql,qr); 71 update (x); 72 } 73 } 74 signed main () { 75 cin >> m; 76 for (I i(1);i <= m; ++ i) 77 cin >> question[i].typ >> question[i].l >> question[i].r; 78 auxiliary[++cnt] = 1; 79 Discretization (); 80 SGT :: found (1,1,cnt); 81 for (I i(1);i <= m; ++ i) { 82 switch (question[i].typ) { 83 case 1 : SGT :: secmod1 (1,1,cnt,question[i].l,question[i].r); break; 84 case 2 : SGT :: secmod2 (1,1,cnt,question[i].l,question[i].r); break; 85 case 3 : SGT :: secmod3 (1,1,cnt,question[i].l,question[i].r); break; 86 } 87 cout << auxiliary[SGT :: pos0[1]] << endl; 88 } 89 }
View Code

注:學習線段樹的核心操作,以及轉移影響的邏輯關係,注意思考問題的全面性