• [bzoj4552][Tjoi2016&Heoi2016]排序-二分+线段树


    Brief Description

    DZY有一个数列a[1..n],它是1∼n这n个正整数的一个排列。
    现在他想支持两种操作:
    0, l, r: 将a[l..r]原地升序排序。
    1, l, r: 将a[l..r]原地降序排序。
    操作完后,他会给你指定一个位置k,请你告诉他a[k]的值。

    Algorithm Design

    很好的一道题目, 反正我没有想到正解, 但是直接抄袭jcvb的bc题目就不太资辞了(连样例都抄也太懒了吧喂) , 附上原题地址.

    这是一道良心的基础数据结构题。
    我们二分a[k]的值,假设当前是mid,然后把大于mid的数字标为1,不大于mid的数字标为0。然后对所有操作做完以后检查一下a[k]位置上是0还是1。
    因为只有两种值,所以操作还是不难做的。只要用一个线段树,支持区间求和、区间赋值即可。这样要排序一个区间时只要查询一下里面有几个1和几个0,然后把前半段赋值为0,后半段赋值为1即可(降序的话就是反过来)。
    复杂度是(O(mlog^2n))的。
    这题用其他玄学做法或者用更加厉害的平衡树做法也是有可能AC的。

    题解来自jcvb的官方题解

    Code

    #include <cstdio>
    #define init int l = t[k].l, r = t[k].r, mid = (l + r) >> 1
    const int maxn = 1e5 + 1e2;
    int n, m, a[maxn], lambda, q;
    struct seg {
      int l, r, val, cov;
    } t[maxn << 4];
    struct op {
      int a, b, c;
    } o[maxn];
    void update(int k) { t[k].val = t[k << 1].val + t[k << 1 | 1].val; }
    void build(int k, int l, int r) {
      t[k].l = l, t[k].r = r, t[k].cov = -1;
      if (l == r) {
        t[k].val = a[l] > lambda;
        return;
      }
      int mid = (l + r) >> 1;
      build(k << 1, l, mid);
      build(k << 1 | 1, mid + 1, r);
      update(k);
    }
    void pushdown(int k) {
      if (t[k].cov != -1) {
        t[k << 1].cov = t[k].cov;
        t[k << 1 | 1].cov = t[k].cov;
        t[k << 1].val = (t[k << 1].r - t[k << 1].l + 1) * (t[k].cov);
        t[k << 1 | 1].val = (t[k << 1 | 1].r - t[k << 1 | 1].l + 1) * (t[k].cov);
        t[k].cov = -1;
      }
      if (t[k].l < t[k].r)
        update(k);
    }
    int query(int k, int x, int y) {
      init;
      pushdown(k);
      if (x <= l && r <= y)
        return t[k].val;
      int ans = 0;
      if (x <= mid)
        ans += query(k << 1, x, y);
      if (y > mid)
        ans += query(k << 1 | 1, x, y);
      return ans;
    }
    void modify(int k, int x, int y, int val) {
      init;
      pushdown(k);
      if (x <= l && r <= y) {
        t[k].val = (r - l + 1) * val;
        t[k].cov = val;
        return;
      }
      if (x <= mid)
        modify(k << 1, x, y, val);
      if (y > mid)
        modify(k << 1 | 1, x, y, val);
      update(k);
    }
    bool check(int x) {
      lambda = x;
      build(1, 1, n);
      for (int i = 1; i <= m; i++) {
        int opt = o[i].a, x = o[i].b, y = o[i].c;
        int tmp = query(1, x, y);
        if (opt == 0) {
          modify(1, x, y - tmp, 0);
          modify(1, y - tmp + 1, y, 1);
        } else {
          modify(1, x, x + tmp - 1, 1);
          modify(1, x + tmp, y, 0);
        }
      }
      return !query(1, q, q);
    }
    int main() {
    #ifndef ONLINE_JUDGE
      freopen("input", "r", stdin);
    #endif
      scanf("%d %d", &n, &m);
      for (int i = 1; i <= n; ++i)
        scanf("%d", &a[i]);
      int l = 1, r = n;
      for (int i = 1; i <= m; i++) {
        scanf("%d %d %d", &o[i].a, &o[i].b, &o[i].c);
      }
      scanf("%d", &q);
      while (l < r) {
        int mid = (l + r) >> 1;
        if (check(mid))
          r = mid;
        else
          l = mid + 1;
      }
      printf("%d", r);
    }
    
  • 相关阅读:
    【Golang】golang文本处理
    【Golang】golang中临时对象池sync.Pool
    WebSocket介绍
    【Linux】linux常用命令操作整理
    【PHP】php7新特性及其优化原理
    【Mysql】MySQL集群方案之PXC(percona xtradb cluster)
    【Linux】线上服务器要关注哪些参数
    service自动发现,yaml文件管理内外部端口访问
    service代理模式及负载均衡
    SET NLS_LANG=AMERICAN_AMERICA.AL32UTF8
  • 原文地址:https://www.cnblogs.com/gengchen/p/6613566.html
Copyright © 2020-2023  润新知