剛碰到區間第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...