【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

271451044
271451044
969056313

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 }
View Code

 

转载于:https://www.cnblogs.com/hoskey/p/4343530.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值