BZOJ 3110: [Zjoi2013]K大数查询

3110: [Zjoi2013]K大数查询

Time Limit: 20 Sec  Memory Limit: 512 MB
Submit: 2276  Solved: 1021

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操作中abs(c)<=Maxlongint

 

解题:整体二分+树状数组改段求段

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const int maxn = 200010;
 4 struct QU {
 5     int x,y,k,id,cache;
 6 } Q[maxn],A[maxn],B[maxn];
 7 int c[2][maxn],ans[maxn];
 8 void add(int *c,int i,int val) {
 9     while(i < maxn) {
10         c[i] += val;
11         i += i&-i;
12     }
13 }
14 int sum(int *c,int i,int ret = 0) {
15     while(i > 0) {
16         ret += c[i];
17         i -= i&-i;
18     }
19     return ret;
20 }
21 void solve(int lt,int rt,int L,int R) {
22     if(lt > rt) return;
23     if(L == R) {
24         for(int i = lt; i <= rt; ++i)
25             if(Q[i].id > -1) ans[Q[i].id] = L;
26         return;
27     }
28     int mid = (L + R)>>1,a = 0,b = 0;
29     for(int i = lt; i <= rt; ++i) {
30         if(Q[i].id == -1) {
31             if(Q[i].k > mid) {
32                 add(c[0],Q[i].x,1);
33                 add(c[0],Q[i].y+1,-1);
34                 add(c[1],Q[i].x,Q[i].x);
35                 add(c[1],Q[i].y+1,-Q[i].y-1);
36                 A[a++] = Q[i];
37             }else B[b++] = Q[i];
38         } else {
39             int tmp = (Q[i].y+1)*sum(c[0],Q[i].y) - sum(c[1],Q[i].y)
40                     - (Q[i].x)*sum(c[0],Q[i].x-1) + sum(c[1],Q[i].x-1);
41             if(tmp + Q[i].cache >= Q[i].k) A[a++] = Q[i];
42             else {
43                 Q[i].cache += tmp;
44                 B[b++] = Q[i];
45             }
46         }
47     }
48     for(int i = lt; i <= rt; ++i) {
49         if(Q[i].id == -1 && Q[i].k > mid) {
50             add(c[0],Q[i].x,-1);
51             add(c[0],Q[i].y+1,1);
52             add(c[1],Q[i].x,-Q[i].x);
53             add(c[1],Q[i].y+1,Q[i].y+1);
54         }
55     }
56     for(int i = 0; i < b; ++i) Q[lt + i] = B[i];
57     for(int i = 0; i < a; ++i) Q[lt + b + i] = A[i];
58     solve(lt,lt+b-1,L,mid);
59     solve(lt+b,rt,mid+1,R);
60 }
61 int main() {
62     int n,m,op,ask = 0;
63     scanf("%d%d",&n,&m);
64     for(int i = 0; i < m; ++i) {
65         scanf("%d%d%d%d",&op,&Q[i].x,&Q[i].y,&Q[i].k);
66         if(op == 2) Q[i].id = ask++;
67         else Q[i].id = -1;
68         Q[i].cache = 0;
69     }
70     solve(0,m-1,-n,n);
71     for(int i = 0; i < ask; ++i) printf("%d\n",ans[i]);
72     return 0;
73 }
View Code

 

posted @ 2015-09-06 09:59  狂徒归来  阅读(197)  评论(0编辑  收藏  举报