• [bzoj2653][middle] (二分 + 主席树)


    Description

      一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整。
      给你一个长度为n的序列s。
      回答Q个这样的询问:s的左端点在[a,b]之间,右端点在[c,d]之间的子序列中,最大的中位数。
      其中a<b<c<d。
      位置也从0开始标号。
      我会使用一些方式强制你在线。

    Input

      第一行序列长度n。
      接下来n行按顺序给出a中的数。
      接下来一行Q。
      然后Q行每行a,b,c,d,我们令上个询问的答案是x(如果这是第一个询问则x=0)。
      令数组q={(a+x)%n,(b+x)%n,(c+x)%n,(d+x)%n}。
      将q从小到大排序之后,令真正的要询问的a=q[0],b=q[1],c=q[2],d=q[3]。
      输入保证满足条件。

    Output

      Q行依次给出询问的答案。

    Sample Input

    5
    170337785
    271451044
    22430280
    969056313
    206452321
    3
    3 1 0 2
    2 3 1 4
    3 1 4 0

    Sample Output

     
    271451044
    271451044
    969056313

    HINT

      0:n,Q<=100

      1,...,5:n<=2000

      0,...,19:n<=20000,Q<=25000

    Solution

     一道神奇的题目,在长沙培训时初次见面

    和一般主席树的做法不尽相同

    为了避免枚举中位数,我们将序列排序,对排序后的点建立一颗以整个序列编号为节点的线段树

    此后,对于每个有序点的线段树,我们将其内的所有值小于它的点的贡献标记为-1,记录从左边起最大连续和,还有从右边起最大连续和

    显然,这个排序后的主席树是满足二分性质的

    那么,我们二分中位数,查询区间[B,C]的贡献、[A,B)的右边最大连续和、(C,D]的左边最大连续和是否大于或等于0,若是,则说明它可以构成一个合法的中位数是当前二分值的序列,也说明中位数大于或等于当前此数

    最后输出二分答案即可

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define N 20200
    #define mid ((s) + (t) >> (1))
    #define dmax(a, b) ((a) > (b) ? (a) : (b))
    
    using namespace std;
    
    inline int Rin(){
      int x = 0, c = getchar(), f = 1;
      for(; c < 48 || c > 57; c = getchar())
        if(!(c ^ 45))f = -1;
      for(; c > 47 && c < 58; c = getchar())
        x = (x << 1) + (x << 3) + c - 48;
      return x * f;
    }
    
    int n;
    
    namespace Arcueid{
      struct Area{
        int lq, rq, sum;
    
        Area(int x = 0){
          lq = rq = dmax(x, 0);
          sum = x;
        }
      };
    
      Area operator + (Area a, Area b){
        Area c;
        c.sum = a.sum + b.sum;
        c.lq = dmax(a.lq, a.sum + b.lq);
        c.rq = dmax(b.rq, a.rq + b.sum);
        return c;
      }
    
      struct Node{
        Node *l, *r;
        Area key;
        Node(){}
        Node(Node *_l, Node *_r, Area _key) : l(_l), r(_r), key(_key) {}
      }*_nil = new Node(), *nil = (*_nil = Node(_nil, _nil, 0), _nil), pool[N * 32], *top = pool, *rt[N];
      Node *newnode(Node *_, Node *__, Area ___){
        *top = Node(_, __, ___);
        return top++;
      }
    
      Node *born(int s, int t){
        if(!(s ^ t))return newnode(0x0, 0x0, Area(1));
        Node *_ = born(s, mid); Node *__ = born(mid + 1, t);
        return newnode(_, __, _->key + __->key);
      }
    
      Node *real(Node *p, int s, int t, int k){
        if(!(s ^ t))return newnode(0x0, 0x0, Area(-1));
        if(k <= mid){
          Node *_ = real(p->l, s, mid, k);
          return newnode(_, p->r, _->key + p->r->key);
        }
        else{
          Node *_ = real(p->r, mid + 1, t, k);
          return newnode(p->l, _, p->l->key + _->key);
        }
      }
    
      Area secret(Node *p, int s, int t, int l, int r){
        if(l == s && t == r)return p->key;
        if(r <= mid)return secret(p->l, s, mid, l, r);
        if(l > mid)return secret(p->r, mid + 1, t, l, r);
        return secret(p->l, s, mid, l, mid) + secret(p->r, mid + 1, t, mid + 1, r);
      }
    
      bool judge(int A, int B, int C, int D, int k){
        int res = 0;
        res += secret(rt[k], 1, n, B, C).sum;
        res += secret(rt[k], 1, n, A, B - 1).rq;
        res += secret(rt[k], 1, n, C + 1, D).lq;
        return res >= 0;
      }
    
      int binsearch(int A, int B, int C, int D){
        int s = 1, t = n;
        while(s + 1 < t){
          if(judge(A, B, C, D, mid))
            s = mid;
          else
            t = mid;
        }
        if(judge(A, B, C, D, t))
          return t;
        return s;
      }
    }
    
    namespace moon{
      struct dat{
        int key, pos;
    
        void init(int _) {key = Rin(); pos = _;}
    
        bool operator < (const dat  h)const{
          return key < h.key;
        }
      }b[N];
    
      void cause(){
        n = Rin();
        for(int i = 1; i <= n; i++)
          b[i].init(i);
        sort(b + 1, b + 1 + n);
        Arcueid::rt[1] = Arcueid::born(1, n);
        for(int i = 2; i <= n; i++)
          Arcueid::rt[i] = Arcueid::real(Arcueid::rt[i - 1], 1, n, b[i - 1].pos);
        int m = Rin(), ans = 0, q[10];
        while(m--){
          for(int j=0;j<4;j++)
            q[j] = Rin(), q[j] = (q[j] + ans) % n+1;
          sort(q,q+4);
          printf("%d
    ", ans = b[Arcueid::binsearch(q[0],q[1],q[2],q[3])].key);
        }
      }
    }
    
    int main(){
      moon::cause();
      return 0;
    }
  • 相关阅读:
    从一个word文件中读取所有的表格和标题(1)
    多线程下QAxObject指针为NULL的解决办法
    event对象,ie8及其以下
    日期插件kalendae,遇到的一些问题
    回车键和button按钮都绑定同一个事件,如何避免按回车的时候button重复点击
    jQuery.Cookie.js用法
    jquery操作radio单选按钮、checked复选框。
    拖拽改变div的大小
    [BZOJ 2242] [SDOI 2011] 计算器
    20181016提高测试
  • 原文地址:https://www.cnblogs.com/keshuqi/p/6245816.html
Copyright © 2020-2023  润新知