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 }
posted @ 2018-10-11 19:35  阿波罗2003  阅读(278)  评论(0编辑  收藏  举报