題目鏈結
題解主席樹入門題
但是這裡給出整體二分解法
整體二分顧名思義是把所有操作放在一起二分
想想,如果求\([1-n]\)的第\(k\)小怎麼二分求得?
我們可以二分答案\(k\), \(o(n)\)統計有多少個數小於等於\(k\)
如果對於每個詢問都這麼搞,肯定不行
我們可以發現,如果每次都搞一次,有許多算重複的地方
\(div(l, r, st, ed)\)表示\(k\)二分的區間\([l-r]\), 對應操作答案區間在\([st-ed]\)
(如果沒看懂,先往下看。)
\(mid = (l+r)/2\)
對於每次的\(mid\), 我們把對\(k\)往左移還有貢獻的 放在一起, 右移的放在一起,這樣答案就在乙個區間內
那麼如何統計一段區間有多少個數比\(k\)大呢?
我們開乙個樹狀陣列,如果\(x\)位上的數大於\(k\),那麼給\(x\)加上1
然後統計就是區間求和了
code
#include#define ll long long
#define rg register
using namespace std;
const int n = 200010, inf = 1e9;
struct rec q[n<<1], lq[n<<1], rq[n<<1];
int n, m, tot, c[n], ans[n];
#define lowbit(x) (x&(-x))
void add(int x, int v)
int sum(int x)
int x[n], cnt;
inline int gi()
void div(int l, int r, int st, int ed)
int mid = (l + r) >> 1;
int lt = 0, rt = 0;
for (int i = st; i <= ed; i++)
else
} for (int i = st; i <= ed; i++)
if (!q[i].op && q[i].y <= mid) add(q[i].x, -1);//清除
for (int i = 1; i <= lt; i++) q[st+i-1] = lq[i];
for (int i = 1; i <= rt; i++) q[st+lt+i-1] = rq[i];
div(l, mid, st, st+lt-1);
div(mid+1, r, st+lt, ed);
return ;
}int main()
sort(x+1, x+1+cnt); cnt = unique(x+1, x+cnt+1)-x-1;//離散化
for (int i = 1; i <= n; i++)
q[i].y = lower_bound(x+1, x+cnt+1, q[i].y)-x;
for (int i = 1; i <= m; i++)
div(1, n, 1, tot);
for (int i = 1; i <= m; i++)
printf("%d\n", x[ans[i]]);
return 0;
}
主席樹 靜態區間第k小
這是個非常經典的主席樹入門題 靜態區間第k小 資料已經過加強,請使用主席樹。同時請注意常數優化 如題,給定n個整數構成的序列,將對於指定的閉區間查詢其區間內的第k小值。輸入格式 第一行包含兩個正整數n m,分別表示序列的長度和查詢的個數。第二行包含n個整數,表示這個序列各項的數字。接下來m行每行包含...
主席樹(區間第k小)
k th number 求區間內第k小的數。主席樹的板子題 主席樹左子樹存小值,右邊大值,用sum記錄一下子樹節點個數。對 l,r 的查詢區間,root r root l 1 可得出 l,r 的差值,也就是大小的個數 include include include include include i...
主席樹 區間第k小
主席樹 權值線段樹 可持久化 權值線段樹 在此處指各個數字在某個區間內出現的次數 那麼第一棵權值線段樹會記錄 1,1 的數字出現次數 第n棵權值線段樹會記錄 1,n 的數字出現次數 例 數列為110001 第一棵權值線段樹記錄為tree1 0 0 tree1 1 1 第二棵權值線段樹記錄為tree2...