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 }
  • 相关阅读:
    LeetCode "Super Ugly Number" !
    LeetCode "Count of Smaller Number After Self"
    LeetCode "Binary Tree Vertical Order"
    LeetCode "Sparse Matrix Multiplication"
    LeetCode "Minimum Height Tree" !!
    HackerRank "The Indian Job"
    HackerRank "Poisonous Plants"
    HackerRank "Kundu and Tree" !!
    LeetCode "Best Time to Buy and Sell Stock with Cooldown" !
    HackerRank "AND xor OR"
  • 原文地址:https://www.cnblogs.com/yyf0309/p/9774586.html
Copyright © 2011-2022 走看看