bzoj 3110[Zjoi2013]K大数查询 - 整体二分

3110: [Zjoi2013]K大数查询

Time Limit: 20 Sec  Memory Limit: 512 MB

Description

有N个位置,M个操作。操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c
如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少。

Input

第一行N,M
接下来M行,每行形如1 a b c或2 a b c

Output

输出每个询问的结果

Sample Input

2 5
1 1 2 1
1 1 2 2
2 1 1 2
2 1 1 1
2 1 2 3

Sample Output

1
2
1

HINT

 



【样例说明】

第一个操作 后位置 1 的数只有 1 , 位置 2 的数也只有 1 。 第二个操作 后位置 1

的数有 1 、 2 ,位置 2 的数也有 1 、 2 。 第三次询问 位置 1 到位置 1 第 2 大的数 是

1 。 第四次询问 位置 1 到位置 1 第 1 大的数是 2 。 第五次询问 位置 1 到位置 2 第 3

大的数是 1 。‍


N,M<=50000,N,M<=50000

a<=b<=N

1操作中abs(c)<=N

2操作中c<=Maxlongint

 

这种问题树套树什么的肯定是无脑刚啊可以用整体二分来做

首先肯定要二分答案,验证 >= mid 的数的个数和 K 的大小关系 

对于一个插入操作,如果他插入的数是比 mid 大的, 那么下一步二分的(l, mid) 的区间这个插入就不会产生贡献

我们可以直接把他放入到 (mid + 1, r) 的区间中,反之同理

如何查询 > mid 的个数呢

用一个线段树维护区间 (l, r) 中> mid数的个数

如果插入的数 > mid 就把他加入到线段树中

查询的时候,如果 > mid 的个数 >= qk 

说明第 qk 个数比mid大, 加入到(mid + 1, r)的区间中

如果少,说明第K大的数在(l, mid) 的区间中, 把qk - > mid的个数

放入到(l, mid)的区间中

 

于是就完成了

 

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <algorithm>
  4 #include <cstring>
  5 #define LL long long
  6 
  7 using namespace std;
  8 
  9 const int MAXN = 5e4 + 10;
 10 const int MAXM = 5e4 + 10;
 11 
 12 int qq[MAXN];
 13 int temp[MAXM];
 14 LL ans[MAXN];
 15 
 16 struct query {
 17     int l, r;
 18     int c;
 19     int opr;    
 20 }  q[MAXN];
 21 
 22 struct segment {
 23     LL sum;
 24     int lazy;
 25     int clear;
 26     void init()
 27     {
 28         sum = 0;
 29         lazy = 0;
 30     }
 31 } seg[MAXN * 10];
 32 
 33 inline LL read()
 34 {
 35     LL x = 0, w = 1; char ch = 0;
 36     while(ch < '0' || ch > '9') {
 37         if(ch == '-') {
 38             w = -1;
 39         }
 40         ch = getchar();
 41     }
 42     while(ch >= '0' && ch <= '9') {
 43         x = x * 10 + ch - '0';
 44         ch = getchar();
 45     }
 46     return x * w;
 47 }
 48 
 49 int N, M;
 50 
 51 void pushdown(int k, LL l, LL r)
 52 {
 53     LL mid = (l + r) >> 1;
 54     if(seg[k].clear) {
 55         seg[k].clear = 0;
 56         seg[k << 1].init(), seg[k << 1 | 1].init();
 57         seg[k << 1].clear = seg[k << 1 | 1].clear = 1;
 58     }
 59     if(seg[k].lazy) {
 60         seg[k << 1].lazy += seg[k].lazy;
 61         seg[k << 1 | 1].lazy += seg[k].lazy;
 62         seg[k << 1].sum += (mid - l + 1) * seg[k].lazy;
 63         seg[k << 1 | 1].sum += (r - mid) * seg[k].lazy;
 64         seg[k].lazy = 0;
 65     }
 66 }
 67 
 68 void pushup(int k)
 69 {
 70     seg[k].sum = seg[k << 1].sum + seg[k << 1 | 1].sum;
 71 }
 72 
 73 LL query(int ql, int qr, int l, int r, int root)
 74 {
 75     //cout<<l<<" "<<r<<endl;
 76     if(ql <= l && qr >= r) {
 77         //cout<<ql<<" "<<qr<<" "<<l<<" "<<r<<" "<<seg[root].sum<<endl;
 78         return seg[root].sum;
 79     }
 80     int mid = (l + r) >> 1;
 81     pushdown(root, l, r);
 82     LL s = 0;
 83     //cout<<mid<<" "<<ql<<" "<<qr<<endl;
 84     if(ql <= mid) {
 85         s += query(ql, qr, l, mid, root << 1);
 86     } 
 87     //cout<<mid<<" "<<ql<<" "<<qr<<endl;
 88     if(qr > mid) {
 89         //cout<<mid<<" "<<ql<<" "<<qr<<endl;
 90         s += query(ql, qr, mid + 1, r, root << 1 | 1);
 91     }
 92     pushup(root);
 93     return s;
 94 }
 95 
 96 void add(int ul, int ur, int l, int r, int root)
 97 {
 98     if(ul <= l && ur >= r) {
 99         seg[root].sum += (r - l + 1);
100         //cout<<ul<<" "<<ur<<" "<<l<<" "<<r<<" "<<seg[root].sum<<endl;
101         seg[root].lazy++;
102         return;
103     }
104     int mid = (l + r) >> 1;
105     pushdown(root, l, r);
106     if(ul <= mid) {
107         add(ul, ur, l, mid, root << 1);
108     }
109     if(ur > mid) {
110         add(ul, ur, mid + 1, r, root << 1 | 1);
111     }
112     pushup(root);
113     return;
114 }
115 
116 void solve(int l, int r, int a, int b)
117 {
118     /*cout<<l<<" "<<r<<" "<<a<<" "<<b<<endl;
119     for(int i = l; i <= r; i++) {
120         cout<<qq[i]<<" ";
121     }
122     cout<<endl<<endl;*/
123     int mid = (a + b) >> 1;
124     if(l > r) {
125         return;
126     }
127     if(a == b) {
128         for(int i = l; i <= r; i++) {
129             int t = qq[i];
130             if(q[t].opr == 2) {
131                 ans[t] = mid;
132             }
133         }
134         return;
135     }
136     int L = l, R = r;
137     seg[1].init();
138     seg[1].clear = 1;
139     for(int i = l; i <= r; i++) {
140         int t = qq[i];
141         if(q[t].opr == 1) {
142             if(q[t].c > mid) {
143                 //cout<<q[t].l<<" "<<q[t].r<<endl;
144                 add(q[t].l, q[t].r, 1, N, 1);
145                 temp[R--] = t;    
146             } else {
147                 temp[L++] = t;
148             }
149         } else {
150         //    cout<<q[t].l<<" "<<q[t].r<<endl;
151             LL num = query(q[t].l, q[t].r, 1, N, 1);
152         //    cout<<num<<endl;
153             if(q[t].c > num) {
154                 q[t].c -= num;
155                 temp[L++] = t;
156             } else {
157                 temp[R--] = t;
158             }
159         }
160     }
161     //cout<<L<<" "<<R<<endl;
162     for(int i = l; i < L; i++) {
163         qq[i] = temp[i];
164     }
165     for(int i = r; i >= L; i--) {
166         qq[i] = temp[++R];
167     }
168     solve(l, L - 1, a, mid);
169     solve(L, r, mid + 1, b);
170 }
171 
172 void open()
173 {
174     freopen("sequence1.in", "r", stdin);
175     freopen("sequence.out", "w", stdout);
176 }
177 
178 int main()
179 {
180     //open();
181     N = read(), M = read();
182     for(int i = 1; i <= M; i++) {
183         q[i].opr = read();
184         q[i].l = read(), q[i].r = read(), q[i].c = read();
185         qq[i] = i;
186     }
187     solve(1, M, -N, N);
188     for(int i = 1; i <= M; i++) {
189         if(q[i].opr == 2) {
190             printf("%lld\n", ans[i]);
191         }
192     }
193     return 0;
194 }
View Code

 

posted @ 2018-03-24 16:14  大财主  阅读(154)  评论(0编辑  收藏  举报