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
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
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 }
夜空中最亮的星,照亮我前行