【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

51703377852714510442243028096905631320645232133 1 0 22 3 1 43 1 4 0

271451044271451044969056313

Sample Output

Hint

  0:n,Q<=100

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

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

Source

【分析】

居然wa了一下TAT.

比较简单的题目,按照权值大小初始化一下线段树将其可持久化,对于二分的版本求前缀和的最大最小值减一下看是否大于等于0就可以了。

  1 /*
  2 唐代贾岛
  3 《剑客 / 述剑》
  4 十年磨一剑,霜刃未曾试。
  5 今日把示君,谁有不平事?
  6 */
  7 #include <iostream>
  8 #include <cstdio>
  9 #include <algorithm>
 10 #include <cstring>
 11 #include <vector>
 12 #include <utility>
 13 #include <iomanip>
 14 #include <string>
 15 #include <cmath>
 16 #include <queue>
 17 #include <assert.h>
 18 #include <map>
 19 #include <ctime>
 20 #include <cstdlib>
 21 #include <stack>
 22 #define LOCAL
 23 const int INF = 0x7fffffff;
 24 const int MAXN = 20000  + 10;
 25 const int maxnode = 20000 * 2 + 200000 * 20;
 26 const int maxm= 30000 * 2 + 10;
 27 using namespace std;
 28 struct DATA{
 29        int num;
 30        int order;
 31        bool operator < (const DATA &b)const{
 32             return num < b.num;
 33        }
 34 }sorted[MAXN];
 35 int data[MAXN];
 36 struct Node{
 37        int l, r;
 38        int Max, val, sum, Min;
 39        Node *ch[2];
 40 }*root[MAXN], mem[maxnode];
 41 int tot, n;
 42
 43 Node *NEW(int l, int r){
 44      Node *p = &mem[tot++];
 45      p->l = l;
 46      p->r = r;
 47      p->val = p->sum = p->Max = p->Min = 1;
 48      p->ch[0] = p->ch[1] = NULL;
 49      return p;
 50 }
 51 void update(Node *&t){
 52      if (t->l == t->r) return;
 53      t->sum = 0;
 54      if (t->ch[0] != NULL) t->sum += t->ch[0]->sum;
 55      if (t->ch[1] != NULL) t->sum += t->ch[1]->sum;
 56
 57      t->Max = max(t->ch[1]->Max + t->ch[0]->sum, t->ch[0]->Max);
 58      t->Min = min(t->ch[1]->Min + t->ch[0]->sum, t->ch[0]->Min);
 59      return;
 60 }
 61 void build(Node *&t, int l, int r){
 62      if (t == NULL){
 63         t = NEW(l, r);
 64      }
 65      if (l == r) return;
 66      int mid = (l + r) >> 1;
 67      build(t->ch[0], l, mid);
 68      build(t->ch[1], mid + 1, r);
 69      update(t);
 70 }
 71 //将l改为-1
 72 void change(Node *&t, Node *&last, int l){
 73      if (t == NULL){
 74            t = NEW(last->l, last->r);
 75            t->val = last->val;
 76            t->Max = last->Max;
 77            t->Min = last->Min;
 78            t->sum = last->sum;
 79      }
 80      if (t->l == l && t->r == l){
 81         t->Min = t->Max = t->sum = -1;
 82         return;
 83      }
 84      int mid = (t->l + t->r) >> 1;
 85      if (l <= mid){
 86         change(t->ch[0], last->ch[0], l);
 87         t->ch[1] = last->ch[1];
 88      }else{
 89         change(t->ch[1], last->ch[1], l);
 90         t->ch[0] = last->ch[0];
 91      }
 92      update(t);
 93 }
 94 int qSum(Node *t, int l, int r){
 95     if (l > r) return 0;
 96     if (l == 0) return qSum(t, l + 1, r);
 97
 98     if (l <= t->l && t->r <= r) return t->sum;
 99     int mid = (t->l + t->r) >>1;
100     int sum = 0;
101     if (l <= mid) sum += qSum(t->ch[0], l, r);
102     if (r > mid) sum += qSum(t->ch[1], l, r);
103     return sum;
104 }
105 int qMax(Node *t, int l, int r, int k){
106      if (l == 0) return max(0, qMax(t, l + 1, r, k));
107
108      if (l <= t->l && t->r <= r) return t->Max + qSum(root[k], 1, t->l - 1);
109      int mid = (t->l + t->r) >> 1;
110      int Ans = -INF;
111      if (l <= mid) Ans = max(Ans, qMax(t->ch[0], l, r, k));
112      if (r > mid) Ans = max(Ans, qMax(t->ch[1], l, r, k));
113      return Ans;
114 }
115 int qMin(Node *t, int l, int r, int k){
116      if (l == 0) return min(0, qMin(t, l + 1, r, k));
117
118      if (l <= t->l && t->r <= r) return t->Min + qSum(root[k], 1, t->l - 1);
119      int mid = (t->l + t->r) >> 1;
120      int Ans = INF;
121      if (l <= mid) Ans = min(Ans, qMin(t->ch[0], l, r, k));
122      if (r > mid) Ans = min(Ans, qMin(t->ch[1], l, r, k));
123      return Ans;
124 }
125
126 void init(){
127      scanf("%d", &n);
128      for (int i = 1; i <= n; i++){
129          sorted[i].order = i;
130          scanf("%d", &sorted[i].num);
131          data[i] = sorted[i].num;
132      }
133      //离散化
134      sort(sorted + 1, sorted + 1 + n);
135
136      tot = 0;
137      root[1] = NULL;
138      build(root[1], 1, n);
139      //开始可持久化
140      for (int i = 2; i <= (n + 1); i++) change(root[i], root[i - 1], sorted[i - 1].order);
141      //printf("%d", root[6]->Max);
142      /*int cnt = 0;
143      for (int i = 1; i <= n; i++){
144          if (i == 0 || sorted[i].num != sorted[i - 1].num) cnt++;
145          rem[cnt] = sorted[i].num;
146          data[sorted[i].order] = cnt;
147      }*/
148      //for (int i = 1; i <= n; i++)
149 }
150 int search(int a, int b, int c, int d){
151     int Ans, l = 1, r = n;
152     while (l <= r){
153           int mid = (l + r) >> 1;
154           if ((qMax(root[mid], c, d, mid) - qMin(root[mid], a, b, mid)) >= 0) Ans = mid, l = mid + 1;
155           else r = mid - 1;
156     }
157     return Ans;
158 }
159 void work(){
160      int last_ans = 0, m;
161      scanf("%d", &m);
162      for (int i = 1; i <= m; i++){
163          int q[5];
164          for (int j = 1; j <= 4; j++){
165              scanf("%d", &q[j]);
166              q[j] = (q[j] + last_ans) % n;
167          }
168          sort(q + 1, q + 1 + 4);
169          int a = q[1], b = q[2], c = q[3], d = q[4];
170          a++;c++;
171          b++;d++;
172          //printf("%d", qMax(root[5], 3, 3, 5));
173          //printf("%d%d%d%d\n", a, b, c, d);
174          last_ans = sorted[search(a - 1, b - 1, c, d)].num;
175          printf("%d\n", last_ans);
176      }
177 }
178
179 int main (){
180
181     init();
182     work();
183     return 0;
184 }

时间: 2024-10-24 07:36:56

【BZOJ2653】【主席树+二分】middle的相关文章

HDU6621 K-th Closest Distance HDU2019多校训练第四场 1008(主席树+二分)

HDU6621 K-th Closest Distance HDU2019多校训练第四场 1008(主席树+二分) 传送门:http://acm.hdu.edu.cn/showproblem.php?pid=6621 题意: 给你n个数,有m次询问 每次问你在区间[l,r]内 第k小的|\(a_i-p\)|是多少 题解: 主席树+二分 每次二分答案 如果p+mid到p-mid的值的个数大于k个的话,mid值就是可行了,然后缩小区间往左找即可 因为保证有解,所以二分出来的mid值就是答案了 que

bzoj 2653 middle (主席树+二分)

版权声明:本文为博主原创文章,未经博主允许不得转载. bzoj 2653 题意: 一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整. 给你一个长度为n的序列s. 回答Q个这样的询问:s的左端点在[a,b]之间,右端点在[c,d]之间的子序列中,最大的中位数. 其中a<b<c<d. 位置也从0开始标号. 强制在线. 解法: 首先可以想到的是二分答案,再判断是否满足条件 . 对于答案x,我们将原数组中大于等于x的数记1,小于的记为-1,

13年山东省赛 Boring Counting(离线树状数组or主席树+二分or划分树+二分)

转载请注明出处: http://www.cnblogs.com/fraud/          ——by fraud 2224: Boring Counting Time Limit: 3 Sec  Memory Limit: 128 MB Description In this problem you are given a number sequence P consisting of N integer and Pi is the ith element in the sequence.

BZOJ1926 [Sdoi2010]粟粟的书架 【主席树 + 二分 + 前缀和】

题目 幸福幼儿园 B29 班的粟粟是一个聪明机灵.乖巧可爱的小朋友,她的爱好是画画和读书,尤其喜欢 Thomas H. Co rmen 的文章.粟粟家中有一个 R行C 列的巨型书架,书架的每一个位置都摆有一本书,上数第i 行.左数第j 列 摆放的书有Pi,j页厚.粟粟每天除了读书之外,还有一件必不可少的工作就是摘苹果,她每天必须摘取一个指定的 苹果.粟粟家果树上的苹果有的高.有的低,但无论如何凭粟粟自己的个头都难以摘到.不过她发现, 如果在脚 下放上几本书,就可以够着苹果:她同时注意到,对于第

HDU - 6621 K-th Closest Distance 主席树+二分答案

K-th Closest Distance 主席树第二波~ 题意 给你\(n\)个数\(m\)个询问,问\(i\in [l,r]\)计算每一个\(|a_{i}-p|\)求出第\(k\)小 题目要求强制在线\(l = l \oplus ans.r = r \oplus ans.p = p \oplus ans.k = k \oplus ans\)(ans为上次询问的答案) 思路 二分答案\(ans\),找区间\(i\in[l,r], a_{i} \in [p-ans, p+ans]\)里的数量\(

主席树+二分 p4602

题意:给出每一种果汁的美味度,价格,升数: m个询问,每个询问给出最高上限的钱g,以及给出最少的w 意思是,最多用g的钱去买最少l的果汁,问能得到的最大美味度: 美味度是取所有果汁中美味度的最小值: 所以这道题有:美味度,价格,升数, 一开始想的时候,因为多了一个条件不知道怎么操作,看了题解之后才发现,将其中的美味度拿来二分了: 也就是说,题目中的美味度取值,是二分出来的: 那么如何建树呢? 因为美味度二分,自然建树的时候是拿美味度作为主体: 也就是说,按美味度从小到大建树(小的美味度可以包括大

[hdu-6621]K-th Closest Distance 主席树 线段树 2019 多校4

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6621 题意:给一个数组,多次询问 l,r,k,p,问 l~r区间 第k小的|p-ai|是多少1<=p.ai<1e6 .1 <= K <= 169, R - L + 1 >= K,1 <= n, m <= 10^5 题解:二分答案+主席树二分绝对值答案r,然后用主席树查[p-r , p+r]区间有多少个数,如果大于等于k个减小r并记录答案,小于k个增大r有一种情况是r满

【BZOJ2653】middle,主席树(非权值线段树)维护区间01信息+二分答案

传送门 写在前面:虽然这是一道我再也不想写的题目,但很好很有价值 思路: cxlove大神: 要求中位数最大,首先二分中位数,然后判断可行不可行. 判断X可行不可行,对于区间内的数,凡是>=X的标为1,否则为-1.这样的话,求一次最大区间和 如果大于等于0,则说明可行. 这要求我们不能像之前那样建立权值线段树的主席树(区间即为权值)了,而是以权值为下标,维护区间[1,n]的信息,可能有点拗口,这里就理解是我们平常写的普通线段树好了,只是这里是n棵由于根的不同而信息不同的线段树 具体实现 对于题目

bzoj2653 -- 二分+主席树

对于每一个询问二分答案. 设当前答案为x,将>=x的数的权值设为1,<x的数的权值设为-1. 当 [b+1,c-1]的权值和+[a,b]权值和最大的后缀+[c,d]权值和最大的前缀>=0时x可行. 先对每个数离散,然后以每个值建立主席树记录区间和.最大前缀.最大后缀就可以了. 时间复杂度:O(n*log3n) 代码: 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #inclu