bzoj 4358 Permu - 莫隊算法 - 鏈表
阿新 • • 發佈:2018-10-11
https query 0ms time spa 位置 color add 不能
題目傳送門
需要高級權限的傳送門
題目大意
給定一個全排列,詢問一個區間內的值域連續的一段的長度的最大值。
考慮使用莫隊算法。
每次插入一個數$x$,對值域的影響可以分成4種情況:
- $x - 1$, $x + 1$都不存在。
- 只有$x - 1$存在,等價於在一段後面添加一個數
- 只有$x + 1$存在,等價於在一段前面添加一個數
- $x - 1$和$x + 1$都存在,等價於把兩段拼起來
所以只有端點處的信息有用。我們考慮維護端點處的信息。
為了方便區分存在和不存在,我們維護開區間。
每個端點的$pre$指向這一段開頭的前一個位置,每個端點的$suf$指向這一段結尾的後一個位置。
然後討論一下就能更新了。
同時發現在保證順序的情況下資瓷刪除。(不能也沒有關系)
然後讓莫隊回滾一下就做完了。時間復雜度$O(m\sqrt{n})$。
Code
1 /** 2 * bzoj 3 * Problem#4358 4 * Accepted 5 * Time: 3600ms 6 * Memory: 2664k 7 */ 8 #include <bits/stdc++.h> 9 using namespace std; 10 typedef bool boolean; 11 12 constint cs = 256; 13 14 typedef class Query { 15 public: 16 int l, r, id, res; 17 18 boolean operator < (Query b) const { 19 if ((l >> 8) != (b.l >> 8)) 20 return (l >> 8) < (b.l >> 8); 21 returnr < b.r; 22 } 23 }Query; 24 25 int n, m; 26 int *ar; 27 int *suf, *pre; 28 Query* qs; 29 30 inline void init() { 31 scanf("%d%d", &n, &m); 32 ar = new int[(n + 1)]; 33 suf = new int[(n + 2)]; 34 pre = new int[(n + 2)]; 35 qs = new Query[(m + 1)]; 36 for (int i = 0; i < n; i++) 37 scanf("%d", ar + i); 38 for (int i = 0; i < m; i++) { 39 scanf("%d%d", &qs[i].l, &qs[i].r); 40 qs[i].l--, qs[i].r--, qs[i].id = i; 41 } 42 } 43 44 boolean exist(int x) { 45 return pre[x] != suf[x]; 46 } 47 48 49 void insert(int x, int& res) { 50 boolean sgnpre = exist(x - 1), sgnsuf = exist(x + 1); 51 if (!sgnpre && !sgnsuf) { 52 pre[x] = x - 1; 53 suf[x] = x + 1; 54 res = max(res, 1); 55 } else if (sgnpre && !sgnsuf) { 56 int front = pre[x - 1]; 57 pre[x] = front, suf[x] = x + 1; 58 suf[front + 1] = x + 1; 59 res = max(res, x - front); 60 } else if (sgnsuf && !sgnpre) { 61 int rear = suf[x + 1]; 62 pre[x] = x - 1, suf[x] = rear; 63 pre[rear - 1] = x - 1; 64 res = max(res, rear - x); 65 } else { 66 int front = pre[x - 1], rear = suf[x + 1]; 67 pre[x] = front, suf[x] = rear; 68 suf[front + 1] = rear, pre[rear - 1] = front; 69 res = max(res, rear - front - 1); 70 } 71 } 72 73 void remove(int x) { 74 boolean sgnpre = exist(x - 1), sgnsuf = exist(x + 1); 75 if (!sgnpre && !sgnsuf) 76 pre[x] = suf[x] = x; 77 else if (sgnpre && !sgnsuf) { 78 int front = pre[x]; 79 pre[x] = suf[x] = suf[front + 1] = x; 80 } else if (sgnsuf && !sgnpre) { 81 int rear = suf[x]; 82 pre[x] = suf[x] = pre[rear - 1] = x; 83 } else { 84 int front = pre[x], rear = suf[x]; 85 pre[x] = suf[x] = x; 86 suf[front + 1] = pre[rear - 1] = x; 87 } 88 } 89 90 inline void solve() { 91 sort(qs, qs + m); 92 Query* q = qs, *ped = qs + m; 93 for (int sid = 0; q != ped; sid++) { 94 int ed = cs * (sid + 1), mdzzr = ed - 1; 95 for (int i = 0; i <= n + 1; i++) 96 pre[i] = suf[i] = i; 97 int cures = 1; 98 for ( ; q != ped && (q->l >> 8) == sid; q++) { 99 if ((q->r >> 8) == sid) { 100 q->res = 1; 101 for (int i = q->l; i <= q->r; i++) 102 insert(ar[i], q->res); 103 for (int i = q->r; i >= q->l; i--) 104 remove(ar[i]); 105 } else { 106 while (mdzzr < q->r) 107 insert(ar[++mdzzr], cures); 108 int nres = cures; 109 for (int i = ed - 1; i >= q->l; i--) 110 insert(ar[i], nres); 111 q->res = nres; 112 for (int i = q->l; i < ed; i++) 113 remove(ar[i]); 114 } 115 } 116 } 117 for (int i = 0; i < m; i++) 118 while (qs[i].id != i) 119 swap(qs[i], qs[qs[i].id]); 120 for (int i = 0; i < m; i++) 121 printf("%d\n", qs[i].res); 122 } 123 124 int main() { 125 init(); 126 solve(); 127 return 0; 128 }
bzoj 4358 Permu - 莫隊算法 - 鏈表