bzoj 3110[Zjoi2013]K大数查询 - 整体二分
3110: [Zjoi2013]K大数查询
Time Limit: 20 Sec Memory Limit: 512 MBDescription
有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操作中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)的区间中
于是就完成了
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }