Codeforces 765F Souvenirs - 莫队算法 - 链表
Posted yyf0309
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces 765F Souvenirs - 莫队算法 - 链表相关的知识,希望对你有一定的参考价值。
不会。。果断莫队(orz mcfx,一讲“值域”链表就明白可以干什么了)。
当插入一个数的时候,如果用set维护前驱后继,然后结果是:$O((n + m)sqrt{n}log n)$,没救的,卡不过去。
但是感觉原序列不会改变,使用set维护很浪费。
考虑链表。注意到链表能够$O(1)$完成插入和删除。
然而这对我们解决问题没什么用,考虑对于按照一定顺序删除,然后逆序恢复这些被删除的点也是可行的。例如我依次删掉1,2,3。然后依次加入3,2,1.这中间我都能正确地找回前驱后继。
这是一条优美的性质。
由于答案不支持删除,考虑回滚莫队。
当左端点在一块内的时候,首先从小到大(不是下标,是数值)建出链表。按照回滚莫队的方式,右端点需要从下一块块首开始向右扩展,因此从1开始,向后删掉链表中的元素,直到当前块块尾。然后从数组尾向前删除元素,直到链表被清空。然后从块尾的后一个位置开始向后加入元素,并记录当前区间的答案(因为你可以在链表中查询一个元素的前驱后继)。
然后从块尾遍历到块首,依次加入元素,然后从后面删掉块外的元素。
预处理部分就结束了,接着考虑处理询问。
- 当询问区间在同一块内时。从块首删到询问的左端点(不包含它),然后从块尾删到询问的左端点。然后反着加入元素,边加边更新答案。最后加到块尾,最后将块左端删掉的一部分加回去。
- 当询问区间跨过块端点时,从移动莫队右指针,加入元素。然后删掉当前块内的所有元素,从块尾加入元素,加到左端点,不断更新左半边产生的答案。那右半边本身的答案呢?之前记录了。然后两者取个最小值就是答案。
确实好像有点繁琐,写起来还是不难受。详情可以看代码,语文不太好讲不清楚。
因为要保证删掉的元素还能正确的找回来,所以需要进行辣么多次感觉是没用的删除。就因为这个常数比普通莫队大个2~3倍以上。然后codeforces上过了,floj上就T掉了。sad。
不过感觉给个空限10M就能卡掉若干主席树做法。(果然最毒瘤的不是卡时间,而是卡空间。)
Code
1 /** 2 * Codeforces 3 * Problem#765F 4 * Accepted 5 * Time: 1309ms 6 * Memory: 9400k 7 */ 8 #include <bits/stdc++.h> 9 using namespace std; 10 typedef bool boolean; 11 12 #define pii pair<int, int> 13 #define fi first 14 #define sc second 15 16 const int cs = 350; 17 const signed int inf = (signed) (~0u >> 1); 18 19 typedef class Query { 20 public: 21 int l, r, lid, rid, id, res; 22 23 boolean operator < (Query b) const { 24 if (lid != b.lid) return lid < b.lid; 25 return r < b.r; 26 } 27 }Query; 28 29 int n, m; 30 int *ar; 31 pii *cr; 32 int *pre, *suf, *L; 33 Query *qs; 34 35 inline void init() { 36 scanf("%d", &n); 37 ar = new int[(n + 1)]; 38 cr = new pii[(n + 1)]; 39 pre = new int[(n + 2)]; 40 suf = new int[(n + 2)]; 41 L = new int[(n + 1)]; 42 for (int i = 1; i <= n; i++) 43 scanf("%d", ar + i), cr[i].fi = ar[i], cr[i].sc = i; 44 scanf("%d", &m); 45 qs = new Query[(m + 1)]; 46 for (int i = 1; i <= m; i++) { 47 scanf("%d%d", &qs[i].l, &qs[i].r); 48 qs[i].lid = (qs[i].l - 1) / cs, qs[i].rid = (qs[i].r - 1) / cs; 49 qs[i].id = i; 50 } 51 } 52 53 void add(int p) { 54 suf[pre[p]] = p; 55 pre[suf[p]] = p; 56 } 57 58 void remove(int p) { 59 suf[pre[p]] = suf[p]; 60 pre[suf[p]] = pre[p]; 61 } 62 63 int update(int p) { 64 int rt = inf; 65 if (pre[p]) 66 rt = ar[p] - ar[pre[p]]; 67 if (suf[p] <= n) 68 rt = min(rt, ar[suf[p]] - ar[p]); 69 return rt; 70 } 71 72 inline void solve() { 73 sort(cr + 1, cr + n + 1); 74 sort(qs + 1, qs + m + 1); 75 int c = 1; 76 for (int sid = 0; sid <= n / cs && c <= m; sid++) { 77 int mdzzr = min(cs * (sid + 1), n), ls = 0, lr = cs * sid, ce = mdzzr; 78 79 pre[0] = 0, ls = 0; 80 for (int i = 1; i <= n; i++) { 81 pre[cr[i].sc] = ls; 82 suf[ls] = cr[i].sc; 83 ls = cr[i].sc; 84 } 85 suf[n + 1] = n + 1, pre[n + 1] = ls, suf[ls] = n + 1; 86 87 for (int i = 1; i <= mdzzr; i++) 88 remove(i); 89 for (int i = n; i > mdzzr; i--) 90 remove(i); 91 L[mdzzr] = inf; 92 for (int i = mdzzr + 1; i <= n; i++) 93 add(i), L[i] = min(L[i - 1], update(i)); 94 for (int i = mdzzr; i > lr; i--) 95 add(i); 96 for (int i = n; i > mdzzr; i--) 97 remove(i); 98 99 for ( ; c <= m && qs[c].lid == sid; c++) { 100 int l = qs[c].l, r = qs[c].r; 101 if (qs[c].lid == qs[c].rid) { 102 for (int i = lr + 1; i < l; i++) 103 remove(i); 104 for (int i = mdzzr; i >= l; i--) 105 remove(i); 106 int res = inf; 107 for (int i = l; i <= r; i++) 108 add(i), res = min(res, update(i)); 109 for (int i = r + 1; i <= mdzzr; i++) 110 add(i); 111 for (int i = l - 1; i > lr; i--) 112 add(i); 113 qs[c].res = res; 114 } else { 115 while (mdzzr < r) 116 add(++mdzzr); 117 int res = inf; 118 for (int i = lr + 1; i <= ce; i++) 119 remove(i); 120 for (int i = ce; i >= l; i--) 121 add(i), res = min(res, update(i)); 122 for (int i = l - 1; i > lr; i--) 123 add(i); 124 qs[c].res = min(res, L[r]); 125 } 126 } 127 } 128 129 for (int i = 1; i <= m; i++) 130 while (qs[i].id != i) 131 swap(qs[i], qs[qs[i].id]); 132 for (int i = 1; i <= m; i++) 133 printf("%d ", qs[i].res); 134 } 135 136 int main() { 137 init(); 138 solve(); 139 return 0; 140 }
以上是关于Codeforces 765F Souvenirs - 莫队算法 - 链表的主要内容,如果未能解决你的问题,请参考以下文章
Codeforces 765F Souvenirs - 莫队算法 - 链表
Souvenirs CodeForces - 765F (线段树好题)