題目描述
權值線段樹套線段樹板子題
首先觀察題目,判斷為二維偏序問題
操作1為區間修改,所以一定是外部線段樹維護權值,內部線段樹維護所在區間,否則時間複雜度**qwq
為方便查詢,雜湊時我採用雜湊每個數的相反數的方法將求第k大轉換為求第k小
詢問可以直接想到的做法就是二分答案,查詢1~ans在區間內的個數,時間複雜度 o(nlog^3n)
嘗試去掉乙個log,思考發現可以直接在權值線段樹上二分,每次查詢左子樹表示的數在區間內的個數p,若p大於等於當前查詢的第k小則直接進入左子樹,否則進入右子樹並將k減p。時間複雜度o(nlog^2n)
內部線段樹採用動態開點,空間複雜度o(nlog^2n) (n、m同階)
但是我第一次寫的樹套樹貌似常數過大,t了7個點,於是又加上了標記永久化,省去了標記下放的時間和不必要的空間浪費。區間修改時直接在經過的節點上修改權值並在原先打標記的節點上打上永久化標記,查詢是將經過的點的標記都加起來乘區間長度再加上詢問區間的權值即為答案。
具體實現見**
#include #include #include #define gc getchar
#define re register
using namespace std;
template void rd(t& s)
template void rd(t& s, args&... args)
int cnt, tot;
#define ll long long
#define new_node(ls, rs, val) (st[++cnt] = node(ls, rs, val), cnt)
const int maxn = 50050;
const int max = 50000000;
struct node
node() {}
}st[max];
struct que
que() {}
}qu[maxn];
int n;
ll hs[maxn];
int tree[maxn << 2];
void modify(int& o, re int l, re int r, re int ll, re int rr)
re int mid = (ll + rr) >> 1;
if (r <= mid)
modify(st[o].ls, l, r, ll, mid);
else
if (l > mid)
modify(st[o].rs, l, r, mid + 1, rr);
else
modify(st[o].ls, l, mid, ll, mid),
modify(st[o].rs, mid + 1, r, mid + 1, rr);
}ll query(re int o, re int l, re int r, re int ll, re int rr, re int tag)
void add(re int o, re int k, re int l, re int r, re int ll, re int rr)
int midsearch(re int o, re int ll, re int rr, re int l, re int r, re int k)
int main()
sort(hs + 1, hs + 1 + tot);
tot = unique(hs + 1, hs + 1 + tot) - hs - 1;
for (re int i = 1; i <= m; ++i)
else
}return 0;
}
洛谷 P3332 ZJOI2013 K大數查詢
題目 k大數查詢 思路 整體二分。維護兩個區間 l,r 和 l,r 分別代表二分的答案區間,和可以滿足答案的詢問區間。在 l,r 上二分m。對於1操作,如果v小於m,在 q.l,q.r 上用線段樹實現區間加一,值賦1,否則賦0。對於2操作,詢問 q.l,q.r 上的數的個數s,若v小於等於s,值賦1...
洛谷P3332 ZJOI2013 K大數查詢
description 帶區間修求區間第kkk大 資料範圍 n 5 104 n leq 5 times 10 4 n 5 104so luti on solution soluti on字首和套主席樹可以解決靜態 樹狀陣列套主席樹可以解決單點修改區間查詢 貌似在這道題,外層套乙個可以區間修改區間查詢...
洛谷P3332 ZJOI2013 K大數查詢
題目大意 有 n 個位置,m 個操作。操作有兩種 2 l r k 詢問 l,r 中第 k 大的數是多少。題解 樹套樹,權值線段樹套位置線段樹,要標記永久化,不然會 tle 卡點 沒有標記永久化,tle 然後處理 tag 部分寫錯 c code include include include name...