bzoj 4358 Permu - 莫队算法 - 链表
考虑使用莫队算法。
每次插入一个数$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 const int 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 return r < 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 }