套主席樹求區間第k小的數的模板,然後求區間[l,r]第k大的數就等於求區間[l,r]第r-l+1-k小的數(下標從1開始)
區間第k小值問題
有n個數,多次詢問乙個區間[l,r]中第k小的值是多少。
查詢區間[l,r]中的第k小值
我們按照從1到n的順序依次將資料插入可持久化的線段樹中,將會得到n+1個版本的線段樹(包括初始化的版本),將其編號為0~n。
可以發現所有版本的線段樹都擁有相同的結構,它們同乙個位置上的結點的含義都相同。
考慮第i個版本的線段樹的結點p,p中儲存的值表示[1,i]這個區間中,p結點的值域中所含的元素個數;
假設我們知道了[1,r]區間中p結點的值域中所含的元素個數,也知道[1,l-1]區間中p結點的值域中所包含的元素個數,顯然用第乙個個數減去第二個個數,就可以得到[l,r]區間中的元素個數。
因此我們對於乙個查詢[l,r],同步考慮兩個根root[l-1]與root[r],用它們同乙個位置的結點的差值就表示了區間[l,r]中的元素個數,利用這個性質,從兩個根節點,向左右兒子中遞迴的查詢第k小數即可。
常數優化的技巧
一種在常數上減小記憶體消耗的方法:
插入值時候先不要一次新建到底,能留住就留住,等到需要訪問子節點時候再建下去。
這樣理論記憶體複雜度依然是o(nlg^2n),但因為實際上很多結點在查詢時候根本沒用到,所以記憶體能少用一些
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define fin freopen("input.txt","r",stdin);
#define fout freopen("output.txt","w+",stdout);
using
namespace
std;
typedef
long
long ll;
const
int inf = 0x3f3f3f3f;
const
int mod = 1e9 + 7;
const
double eps=1e-8;
const
double pi=acos(-1.0);
const
int maxn=50002;
struct node
tr[maxn*20];
int cur,root[maxn];
inline
void push_up(int o)
int build(int l,int r)
int mid=(l+r)>>1;
tr[k].ls=build(l,mid);
tr[k].rs=build(mid+1,r);
push_up(k);
return k;
}int update(int o,int l,int r,int pos,int val)
int mid=(l+r)>>1;
if(pos<=mid)
tr[k].ls=update(tr[o].ls,l,mid,pos,val);
else
tr[k].rs=update(tr[o].rs,mid+1,r,pos,val);
push_up(k);
return k;
}int query(int l,int r,int o,int v,int kth)
int num[maxn];
int sortnum[maxn];
int main()
sort(sortnum+1,sortnum+1+n);
int cnt=1;
for(int i=2;i<=n;i++)
root[0]=build(1,cnt);
for(int i=1;i<=n;i++)
int q;
scanf("%d",&q);
for(int i=0;iint l,r,k;
scanf("%d %d %d",&l,&r,&k);
int idx=query(1,cnt,root[l],root[r+1],r-l+1-k+1);//模板的下標從1開始,則求的是root[l-1]與root[r]的值
printf("%d\n",sortnum[idx]);}}
}
區間第k大(主席樹)
學了一下主席樹模板題,當初看了網上的主席樹講解都沒有看懂,後面看了嗶哩嗶哩的uestc的主席樹,終於看懂了思想。每次更新的複雜度都為logn。每次更新的話就是對要更新的點路徑上的點重新更加乙個,然後進行對沒有影響的那些進行連邊。然後用乙個root記錄每乙個線段樹的根節點下標。include incl...
主席樹區間第K大
主席樹的實質其實還是一顆線段樹,然後每一次修改都通過上一次的線段樹,來新增新邊,使得每次改變就改變logn個節點,很多節點重複利用,達到節省空間的目的。1.不帶修改的區間第k大。hdu 2665 模板題 1 include2 using namespace std 3 define fopen fr...
主席樹求區間第k大
主席樹是可持久化線段樹,維護 權值個數 線段樹的字首和。相當於對每個區間 1,i 建立n顆線段樹。我們用乙個區間內的數的出現個數建線段樹,所以資料大小較大時一般進行離散化。建的是權值線段樹,即用數值作為區間,每個節點存該數出現的次數,所以query返回的其實是離散後的陣列b的下標idx,最終結果為b...