區間第k小類問題總結

2021-09-11 06:46:27 字數 3129 閱讀 8521

剛碰到區間第k小的問題的時候只會區間sort,後來才掌握了一些解決此類問題的方法。

區間第k小有的題目帶修改有的不帶修改,不論是什麼,都有對應的解決方法。

1.我們可以分塊。分成根號n塊,塊內排序。

對於每次查詢l,r我們二分答案(二分乙個值,統計區間內比他小的個數)。

對於不完整的區間,我們掃一遍統計,對於完整的塊我們直接二分。

那麼對與每乙個修改來說,就直接在原陣列中更改,並且把當前塊重新排序。

**:zoj 2112

#include#include#include#include#include#include#include#include#includeusing namespace std;

#define rep(i,j,k) for(int i=j;i<=k;i++)

#define sca(x) scanf("%d",&x)

#define pb(x) push_back(x)

#define per(i,j,k) for(int i=j;i>=k;i--)

#define inf 0x3f3f3f3f

#define ll long long

#define n 50005

#define inf 0x3f3f3f3f

int len;

int a[n],b[n];

vectorv[255];

void init(int n)

void reset(int x)

void modify(int x,int y)

int query(int l,int r,int k)

rep(i,b[l]+1,b[r]-1)

return ans;

}void work(int m)

printf("%d\n",ans);

}else

}}int main()

}

2.劃分樹

不明白劃分樹的可以去學習,乙個用來求區間第k小的資料結構。

#include#include#include#includeusing namespace std;

#define n 100005

int t[20][n];

int cnt[20][n];

int sor[n];

void build(int l,int r,int dep)

else

}build(l,m,dep+1);

build(m+1,r,dep+1);

}int query(int l,int r,int ql,int qr,int k,int dep)

else

}int main()

sort(sor+1,sor+1+n);

build(1,n,0);

while(m--)

}}

3.整體二分

我理解不太深刻,但是說一下我自己的理解:整體二分我們每次二分乙個答案,如果當前操作為新增乙個值,如果當前的值小於m我們就把它放在左邊(並且在它的位置上加一,這個是為了統計區間的數有幾個),否則的話就放在右邊。如果當前操作為查詢的話,我們就查詢當前l-r裡邊已經插入了多少個數,如果個數大於k的話就放入左邊(這個有點像主席樹上的查詢操作),否則的話就把左邊的數對當前查詢的貢獻減掉放入右邊。最後我們把bit還原,並且遞迴處理左邊和右邊就行。

這個部落格講的很清楚:整體二分

#include#include#include#includeusing namespace std;

#define ll long long

#define sca(x) scanf("%d",&x)

#define lowb(x) (x&(-x))

#define pb(x) push_back(x)

#define rep(i,j,k) for(int i=j;i<=k;i++)

#define pri(x) printf("%d\n",x);

#define n 100005

#define inf 0x3f3f3f3f

const ll mod=1e9+7;

struct node

q[n],q1[n],q2[n];

int a[n];

struct bit

void add(int x,int v)

int ask(int x)

}bit;

int ou[n];

void solve(int ql,int qr,int l,int r)

return ;

}int m=(l+r)>>1;

int l=0,r=0;

rep(i,ql,qr)

else q2[r++]=q[i];

}else

else q[i].k-=res,q2[r++]=q[i];}}

rep(i,0,l-1)if(q1[i].t==1)bit.add(q1[i].id,-q1[i].y);

int now=ql;

rep(i,0,l-1)q[now++]=q1[i];

rep(i,0,r-1)q[now++]=q2[i];

solve(ql,ql+l-1,l,m);

solve(ql+l,ql+l+r-1,m+1,r);

}int main()

; }

char ch=getchar();

char s[3];

int x,y,z;

int qid=1;

rep(i,1,m);}

else

;a[x]=y;

q[tot++]=node;}}

solve(1,tot-1,-inf,inf);

rep(i,1,qid-1)pri(ou[i]);

}}

4.主席樹

對於不帶修改的區間第k小可以用主席樹解決,如果是帶修改的就要用樹套樹。

具體就是:首先對原來的數離散化。

對於每個點我們都建立一顆線段樹,用來記錄區間數的個數,就是乙個字首樹。然後對於乙個查詢區間第k大,(第r棵樹和第l-1棵樹的差就是l-r裡邊範圍離散化後在(1-n)的個數)。。。。先不寫了,,吃飯去了。。

模板 區間第k小

我實在是太弱了現在才會這個東西qaq。主席樹做法。一張關於主席樹的無字說明 線段樹 2 是只單點修改了實心酒紅色點的線段樹 2 線段樹 2 中的藍色節點實際上就是線段樹 1 的藍色節點,我們只是把位址複製過來了。我們多開了乙個線段樹,但是節點數量卻只多了 log 層,那麼對於 n 的歷史版本保留就提...

主席樹(區間第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...