题目传送门

  神速的列车

  光速的列车

  声速的列车

题目大意

  给定一个长度为$n$的序列,$m$次询问区间$[l, r]$内相差最小的两个数的差的绝对值。

Solution 1 Mo's Algorithm & Linked List

  不会。。果断莫队

  当插入一个数的时候,如果用set维护前驱后继,然后结果是:$O((n + m)\sqrt{n}\log n)$,没救的,卡不过去。

  但是感觉原序列不会改变,使用set维护很浪费。

  考虑链表,链表上的每个数的后继是这个数的后继。

  考虑可以通过排序提前得到大小关系,不断从链表中删数就能得到它在剩下的区间内的前后继。如果询问在同一个块内直接暴力。否则把答案分成三部分。

  • 两个数都在当前块外,先从小到大加入剩下的所有数,从右到左删掉它们,再从左到右不断加入它们,然后就能得到所有前缀的答案。
  • 两个数都在当前块内,处理出所有后缀的答案,做法类似。
  • 一个在当前块内,一个在块外,移动右指针的时候让块内的所有数在链表内,查询的时候删掉再加入。

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\n", qs[i].res);
134 }
135 
136 int main() {
137     init();
138     solve();    
139     return 0;
140 }
Mo's Algorithm

相关文章: