線段樹求解區間第k大

2021-07-10 11:18:42 字數 1513 閱讀 3120

具體哪道題目就不說了,區間第k大可以說是很常見的題目。寫了一上午線段樹終於是記起了一點以前學過的東西。

這裡說的是沒有修改的區間查詢。對於線段樹的結構體,一開始搜了一下,說是要按照歸併排序的方法去建樹,所以說每個節點要記錄陣列咯??這樣的話每個節點還要記乙個陣列,太麻煩,空間占用也變大了。所以有另一種方法,直接用乙個陣列,在節點中記錄該節點對應的該陣列中的範圍,這樣就可以節省空間。

建好樹之後就是查詢,這裡要到兩個查詢,第乙個是查詢給定值在給定範圍內的下標,第二個查詢是第乙個查詢中要呼叫的,用來尋找在具體的某乙個節點中它的下標。最後在主程式中二分答案,找到其在給定範圍的下標,判斷即可。

#include#include#define maxn 10100

#define inf 1111111111

struct s;

s tr[maxn*4];

int d[maxn*20],cnt;

int a[maxn];

void build(int rt,int lr,int rr)

int mid=(tr[rt].l+tr[rt].r)>>1;

build(rt*2,lr,mid);

build(rt*2+1,mid+1,rr);

tr[rt].ll=cnt+1;

// printf("cnt==%d\n",cnt);

int l1=tr[rt*2].ll,r1=tr[rt*2].rr;

int l2=tr[rt*2+1].ll,r2=tr[rt*2+1].rr;

while(l1<=r1&&l2<=r2)

return ls-ll;

}int query1(int rt,int ls,int rs,int ans)

int mid=(tr[rt].l+tr[rt].r)>>1;

int hh=0;

if(ls<=mid) hh+=query1(rt*2,ls,rs,ans);

if(rs>=mid+1) hh+=query1(rt*2+1,ls,rs,ans);

return hh;

}int main(){

int n,x,y,k;

cnt=0;

scanf("%d",&n);

for(int i=1;i<=n;i++) scanf("%d",&a[i]);

build(1,1,n);

int m;

scanf("%d",&m);

while(m--){

scanf("%d%d%d",&x,&y,&k);

k=y-x-k+2;

// printf("k==%d\n",k);

int lll=-inf,rrr=inf,mid;

while(lll>1;

int tmp=query1(1,x,y,mid);

// printf("lll===%d rrr====%d mid==%d tmp==%d\n",lll,rrr,mid,tmp);

if(tmp

加油,馬上藍橋杯。

區間第k大(主席樹)

學了一下主席樹模板題,當初看了網上的主席樹講解都沒有看懂,後面看了嗶哩嗶哩的uestc的主席樹,終於看懂了思想。每次更新的複雜度都為logn。每次更新的話就是對要更新的點路徑上的點重新更加乙個,然後進行對沒有影響的那些進行連邊。然後用乙個root記錄每乙個線段樹的根節點下標。include incl...

主席樹區間第K大

主席樹的實質其實還是一顆線段樹,然後每一次修改都通過上一次的線段樹,來新增新邊,使得每次改變就改變logn個節點,很多節點重複利用,達到節省空間的目的。1.不帶修改的區間第k大。hdu 2665 模板題 1 include2 using namespace std 3 define fopen fr...

可持久化線段樹求區間第k大

老爺口諭,有n個數 10 9 n 10 9,每個數的範圍在 0,10 5 給定m個詢問,每次詢問區間 l,r 的第k小值 可持久化線段樹,舔的老爺的模板 1 include2 include3 using namespace std 4 define maxn 100005 5int val max...