zoukankan      html  css  js  c++  java
  • bzoj 4358 Permu

    题目传送门

      需要高级权限的传送门

    题目大意

      给定一个全排列,询问一个区间内的值域连续的一段的长度的最大值。

      考虑使用莫队算法。

      每次插入一个数$x$,对值域的影响可以分成4种情况:

    • $x - 1$, $x + 1$都不存在。
    • 只有$x - 1$存在,等价于在一段后面添加一个数
    • 只有$x + 1$存在,等价于在一段前面添加一个数
    • $x - 1$和$x + 1$都存在,等价于把两段拼起来

      所以只有端点处的信息有用。我们考虑维护端点处的信息。

      为了方便区分存在和不存在,我们维护开区间。

      每个端点的$pre$指向这一段开头的前一个位置,每个端点的$suf$指向这一段结尾的后一个位置。

      然后讨论一下就能更新了。

      同时发现在保证顺序的情况下资瓷删除。(不能也没有关系)

      然后让莫队回滚一下就做完了。时间复杂度$O(msqrt{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
    ", qs[i].res);
    122 }
    123 
    124 int main() {
    125     init();
    126     solve();
    127     return 0;
    128 }
  • 相关阅读:
    JS中iframe子页面与父页面之间通信
    .NET 大数据量并发解决方案
    angular的性能分析 -随记
    第二次作业
    自我介绍
    总结作业
    2019春第四次课程设计实验报告
    2019春第三次课程设计实验报告
    2019春第二次课程设计实验报告
    第十二周作业
  • 原文地址:https://www.cnblogs.com/yyf0309/p/9774586.html
Copyright © 2011-2022 走看看