BZOJ3196二逼平衡樹 樹套樹

2021-08-21 03:33:32 字數 3413 閱讀 2184

description

您需要寫一種資料結構(可參考題目標題),來維護乙個有序數列,其中需要提供以下操作:

1.查詢k在區間內的排名

2.查詢區間內排名為k的值

3.修改某一位值上的數值

4.查詢k在區間內的前驅(前驅定義為小於x,且最大的數)

5.查詢k在區間內的後繼(後繼定義為大於x,且最小的數)

input

第一行兩個數 n,m 表示長度為n的有序序列和m個操作

第二行有n個數,表示有序序列

下面有m行,opt表示操作標號

若opt=1 則為操作1,之後有三個數l,r,k 表示查詢k在區間[l,r]的排名

若opt=2 則為操作2,之後有三個數l,r,k 表示查詢區間[l,r]內排名為k的數

若opt=3 則為操作3,之後有兩個數pos,k 表示將pos位置的數修改為k

若opt=4 則為操作4,之後有三個數l,r,k 表示查詢區間[l,r]內k的前驅

若opt=5 則為操作5,之後有三個數l,r,k 表示查詢區間[l,r]內k的後繼

output

對於操作1,2,4,5各輸出一行,表示查詢結果

sample input

9 64 2 2 1 9 4 0 1 1

2 1 4 3

3 4 10

2 1 4 3

1 2 5 9

4 3 9 5

5 2 8 5

sample output

9 hint

1.n和m的資料範圍:n,m<=50000

2.序列中每個數的資料範圍:[0,1e8]

3.雖然原題沒有,但事實上5操作的k可能為負數

由於這題既要維護區間的資訊,又要搞排名,前驅,後繼等平衡樹的操作。所以這題的思路就是線段樹套平衡樹(樹套樹)

我們對於線段樹的每乙個區間都建立乙個平衡樹,那麼我們就可以進行操作了。我們乙個乙個來看:

操作1:我們查詢線段樹的區間,將每一小塊區間裡小於x的數累加,再加1(x自己)即可。

現在我們來講操作2:直接二分答案,二分乙個權值,然後查詢區間裡有的排名,如果剛好等於k,那麼就讓r=mid,這樣可以保證最終的點取到所求的x的權值vx(因為vx-1的排名肯定是x的排名-1)

int getpl(int l,int r,int k)

return cl-1;

}

code:
#include

#define maxn 3000005

#define inf 2147483647

using namespace std;

intread()

int n,m,mx,dist,tot,a[maxn],rt[maxn];

int son[maxn][2],fa[maxn],val[maxn],siz[maxn],ct[maxn];

void clear(int k)

void pushup(int k)

void rotate(int k)

void splay(int i,int k,int top)

if(!top) rt[i]=k;

}void splayinsert(int p,int

x) int

last=0;

while(1)

last=wh;wh=son[wh][x>val[wh]];

if(!wh)

}splay(p,wh,0);

}int splayrank(int p,int k)

else

if(val[wh]==k) return ret+(son[wh][0]?siz[son[wh][0]]:0);}}

return ret;

}int access(int p,int

x) wh=son[wh][x>val[wh]];

}}int pre(int p)

void splaydelete(int p,int elemental)

if(!son[x][0]&&!son[x][1])

if(!son[x][0])

if(!son[x][1])

int wh=pre(p),oldrt=rt[p];

splay(p,wh,0);

son[rt[p]][1]=son[oldrt][1];fa[son[oldrt][1]]=rt[p];

clear(oldrt);pushup(rt[p]);

}int getpre(int p,int

x) else wh=son[wh][0];

}return dist;

}int getsuff(int p,int

x) else wh=son[wh][1];

}return dist;

}void seginsert(int k,int l,int r,int p,int

x)void segrank(int k,int l,int r,int l,int r,int

x) int mid=(l+r)>>1;

if(l<=mid) segrank(k<<1,l,mid,l,r,x);

if(r>mid) segrank(k<<1|1,mid+1,r,l,r,x);

}void segtransform(int k,int l,int r,int p,int

x) int mid=(l+r)>>1;

if(p<=mid) segtransform(k<<1,l,mid,p,x);

else segtransform(k<<1|1,mid+1,r,p,x);

}void segpre(int k,int l,int r,int l,int r,int

x) int mid=(l+r)>>1;

if(l<=mid) segpre(k<<1,l,mid,l,r,x);

if(r>mid) segpre(k<<1|1,mid+1,r,l,r,x);

}void segsuff(int k,int l,int r,int l,int r,int

x) int mid=(l+r)>>1;

if(l<=mid) segsuff(k<<1,l,mid,l,r,x);

if(r>mid) segsuff(k<<1|1,mid+1,r,l,r,x);

}int getpl(int l,int r,int k)

return cl-1;

}int main()

for(int i=1;i<=m;i++)

if(type==2)

if(type==3)

if(type==4)

if(type==5)

}return

0;}

BZOJ 3196 二逼平衡樹 樹套樹

description 您需要寫一種資料結構 可參考題目標題 來維護乙個有序數列,其中需要提供以下操作 1.查詢k在區間內的排名 2.查詢區間內排名為k的值 3.修改某一位值上的數值 4.查詢k在區間內的前驅 前驅定義為小於x,且最大的數 5.查詢k在區間內的後繼 後繼定義為大於x,且最小的數 in...

樹套樹 BZOJ3196 二逼平衡樹

您需要寫一種資料結構 可參考題目標題 來維護乙個有序數列,其中需要提供以下操作 1.查詢 x在區間內的排名 2.查詢區間內排名為 k 的值 3.修改某一位置上的數值 4.查詢 x 在區間內的前趨 前趨定義為小於 x,且最大的數 5.查詢 x 在區間內的後繼 後繼定義為大於 x,且最小的數 第一行兩個...

Bzoj3196 二逼平衡樹

您需要寫一種資料結構 可參考題目標題 來維護乙個有序數列,其中需要提供以下操作 1.查詢k在區間內的排名 2.查詢區間內排名為k的值 3.修改某一位值上的數值 4.查詢k在區間內的前驅 前驅定義為小於x,且最大的數 5.查詢k在區間內的後繼 後繼定義為大於x,且最小的數 額,這個題,看了一眼就知道是...