zoukankan      html  css  js  c++  java
  • 题解【bzoj2653 middle】

    Description

    给你一个序列,每次询问给出四个数 (a,b,c,d),求所有区间 ([l,r]) 满足 (l in [a,b], r in [c,d]) 的中位数的最大值。强制在线

    (n leq 20000, Q leq 25000,a_i leq 10^9)

    Solution

    考虑二分答案。假设现在二分出来的是 (x) ,那么把 (ge x) 的位置设成 (1)(< x) 的设为 (-1) 。那么一个区间的中位数 (ge x) 等价于这个区间的和 (ge 0)

    如何处理题目给的左右端点的限制?

    可以发现 ([l,r]) 必然包含 ([b+1,c-1]) (如果 (b+1 leq c+1) 的话)所以 ([l, r]) 的和必然包含 ([b+1, c-1]) 的和

    显然让 ([l,r]) 的和最大的方案是取 ([a,b]) 的最大右段和 和 ([c,d]) 的最大左段和

    这些都可以用线段树维护。但这样需要每个数都开一颗线段树,空间爆炸。

    把数组排序,这样每个数的线段树显然只是由前一个数的线段树把一个点的权值从 (1) 改为 (-1) 。可以使用主席树的思想(貌似就是主席树

    然后就做完了。复杂度 (O(m log^2 n))

    Code

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 2000; 
    int n, m; int q[4]; 
    struct Node {
      int d, id; 
    } a[N]; 
    inline bool cmp(Node x, Node y) { 
      return x.d < y.d; 
    }
    struct node {
      int left, right; 
      int sm, lm, rm; 
      node *ch[2]; 
      inline void upd() {
        sm = ch[0]->sm + ch[1]->sm; 
        lm = max(ch[0]->lm, ch[0]->sm + ch[1]->lm);
        rm = max(ch[1]->rm, ch[1]->sm + ch[0]->rm); 
      }
    } *rt[N], pool[N * 50], *cur = pool, *ans; 
    inline void B (node *r, int left, int right) { 
      r->left = left, r->right = right; 
      if(left == right) { r->sm = r->lm = r->rm = 1; return ; }
      node *lson = cur++, *rson = cur++; 
      int mid = (left + right) >> 1;
      r->ch[0] = lson, r->ch[1] = rson;
      B(lson, left, mid), B(rson, mid + 1, right);  r->upd(); 
    }
    inline void I (node *pre, node *now, int pos) { 
      now->left = pre->left, now->right = pre->right; 
      if(now->left == now->right) {
        now->sm = now->lm = now->rm = -1; return ; 
      } int mid = (pre->left + pre->right) >> 1; 
      if(pos <= mid) now->ch[1] = pre->ch[1], I(pre->ch[0], now->ch[0] = cur++, pos); 
      if(pos >  mid) now->ch[0] = pre->ch[0], I(pre->ch[1], now->ch[1] = cur++, pos); 
      now->upd(); 
    }
    inline node* Q (node *now, int l, int r) {
      if(now->left == l && now->right == r) return now; 
      if(now->ch[0]->right >= r) return Q(now->ch[0], l, r);
      else if(now->ch[1]->left <= l) return Q(now->ch[1], l, r); 
      else {
        node *ret = cur++, *L, *R;
        L = Q(now->ch[0], l, now->ch[0]->right);
        R = Q(now->ch[1], now->ch[1]->left, r);
        ret->sm = L->sm + R->sm; 
        ret->lm = max(L->lm, L->sm + R->lm);
        ret->rm = max(R->rm, R->sm + L->rm); 
        return ret; 
      }
    }
    inline bool check(int id) {
      int sum = 0;
      if(q[2] + 1 <= q[3] - 1) sum += Q (rt[id - 1], q[2] + 1, q[3] - 1)->sm; 
      sum += Q (rt[id - 1], q[1], q[2])->rm; 
      sum += Q (rt[id - 1], q[3], q[4])->lm; 
      return sum >= 0; 
    }
    int main() {
      scanf("%d", &n);
      for(int i = 1; i <= n; i++) {
        scanf("%d", &a[i].d); 
        a[i].id = i; 
      } sort(a + 1, a + n + 1, cmp);
      B(rt[0] = cur++, 1, n); 
      for(int i = 1; i <= n; i++) {
        rt[i] = cur++; I(rt[i - 1], rt[i], a[i].id);  
      } 
      int ans = 0; scanf("%d", &m); 
      for(int i = 1; i <= m; i++) {
        for(int j = 1; j <= 4; j++) {
          scanf("%d", &q[j]), 
          q[j] += ans, q[j] %= n; q[j]++; 
        }
        sort(q + 1, q + 4 + 1); 
        int l = 1, r = n; 
        while(l <= r) {
          int mid = (l + r) / 2; 
          if(check(mid)) l = mid + 1, ans = a[mid].d; 
          else r = mid - 1; 
        } printf("%d
    ", ans); 
      }
      return 0; 
    }
    
    
  • 相关阅读:
    java矩阵运算包ujmp中的一些小示例和注意事项
    CSS文字段落排版常用设置
    HTML中标签元素的分类
    三种CSS样式-内联、嵌入、外部
    MySQL常用命令
    解决谷歌浏览器在win8下没有注册类的问题
    转:jQuery.lazyload详解使用方法
    php取整
    限制表单Input的长度,当达到一定长度时不能再输入
    滑动后定位
  • 原文地址:https://www.cnblogs.com/acfunction/p/10294753.html
Copyright © 2011-2022 走看看