BZOJ-3110-K大数查询-ZJOI2013-整体二分
生活随笔
收集整理的這篇文章主要介紹了
BZOJ-3110-K大数查询-ZJOI2013-整体二分
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
描述
有N個位置,M個操作。操作有兩種,每次操作如果是1 a b c的形式表示在第a個位置到第b個位置,每個位置加入一個數c
如果是2 a b c形式,表示詢問從第a個位置到第b個位置,第C大的數是多少。
分析
- 今天終于看懂了一個整體二分的題目. 發現這真是一種很BT的做法.
- 二分答案區間(L, R),?判斷中間值M = L+(R-L)/2. 每次清空線段樹(直接在根節點上打刪除標記, 不要用memset直接清, 會T..). ?線段樹維護的是在區間(a, b)中比二分的答案M大的數有多少.?處理在(l, r)中的操作, 如果是插入(a, b, c), 判斷c和M的大小, c大于M的話在線段樹(a, b)區間打增加標記表示+1, 同時操作類型標記為1, c不大于M操作類型標記為0; 如果是查詢(a, b, c)操作, 當在線段樹(a, b)區間和大于c則說明比M大的超過k個, 那么答案一定比M大, 操作類型標記為1, 否則標記為0.
- 將所有標記為0的點去下一層(L, M)繼續 (可以直接按類型sort, 也可以借鑒歸并排序的思想O(n)的歸并), 標記為1的點去(M+1, R)繼續二分.
- 當答案區間(L = R)時, 操作區間所有的查詢操作的答案都為L.
- 另 : 1. 在線段樹操作時傳入太多參數會嚴重拖慢效率.
- ? ? ? 2. 在結構體里定義的宏在外面一樣用.
代碼
#include #include #include using namespace std;const int maxn = 50000 + 10;#define M (L+((R-L)>>1))struct SegmentTree {int y1, y2;int sumv[maxn<<2], addv[maxn<<2];bool clr[maxn<<2];void init() {sumv[1] = addv[1] = 0;clr[1] = 1;}#define lc (o<<1)#define rc (o<<1^1)void update(int o) {sumv[o] = sumv[lc] + sumv[rc];}void pushdown(int o, int L, int R) {if(clr[o]) {sumv[lc] = sumv[rc] = addv[lc] = addv[rc] = 0;clr[lc] = clr[rc] = 1;clr[o] = 0;}if(addv[o]) {int& x = addv[o];addv[lc] += x;addv[rc] += x;sumv[lc] += (M-L+1) * x;sumv[rc] += (R-M) * x;x = 0;}}void modify(int o, int L, int R) {if(y1 <= L && R <= y2) {addv[o]++;sumv[o] += (R-L+1);} else {pushdown(o, L, R);if(y1 <= M) modify(lc, L, M);if(y2 > M) modify(rc, M+1, R);update(o);}}int query(int o, int L, int R) {if(y1 <= L && R <= y2) return sumv[o];pushdown(o, L, R);int ret = 0;if(y1 <= M) ret += query(lc, L, M);if(y2 > M) ret += query(rc, M+1, R);return ret;}} seg;struct Node {int opt, id, l, r, v, k;bool operator < (const Node& rhs) const {if(k != rhs.k) return k < rhs.k;return id < rhs.id;} } qst[maxn];int n, m; int ans[maxn];void solve(int L, int R, int l, int r) {if(l > r) return;if(L == R) {for(int i = l; i <= r; i++) {Node& x = qst[i];if(x.opt == 2) ans[x.id] = L;}return;}seg.init();int t = l-1;for(int i = l; i <= r; i++) {Node& x = qst[i];if(x.opt == 1) {if(x.v > M) {seg.y1 = x.l;seg.y2 = x.r;seg.modify(1, 1, n);x.k = 1;} else {x.k = 0; t++;}} else {seg.y1 = x.l;seg.y2 = x.r;int s = seg.query(1, 1, n);if(x.v <= s) x.k = 1;else x.k = 0, t++, x.v -= s;}}sort(qst + l, qst + r + 1);solve(L, M, l, t);solve(M+1, R, t+1, r); }int main() {scanf("%d %d", &n, &m);for(int i = 1; i <= m; i++) {int opt, l, r, v;scanf("%d %d %d %d", &opt, &l, &r, &v);qst[i] = (Node) {opt, i, l, r, v};}memset(ans, -1, sizeof(ans));solve(0, n, 1, m);for(int i = 1; i <= m; i++)if(ans[i] != -1) printf("%d\n", ans[i]);return 0; }
總結
以上是生活随笔為你收集整理的BZOJ-3110-K大数查询-ZJOI2013-整体二分的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: BZOJ-2705-Longge的游戏-
- 下一篇: BZOJ-1492-货币兑换cash-N