二逼平衡樹【樹套樹】
問題描述
您需要寫一種資料結構(可參考題目標題),來維護一個有序數列,其中需要提供以下操作:
1.查詢k在區間內的排名
2.查詢區間內排名為k的值
3.修改某一位值上的數值
4.查詢k在區間內的前驅(前驅定義為小於x,且最大的數)
5.查詢k在區間內的後繼(後繼定義為大於x,且最小的數)
輸入格式
第一行兩個數 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的後繼
輸出格式
對於操作1,2,4,5各輸出一行,表示查詢結果
樣例輸入 1
9 6
4 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
樣例輸出 1
2
4
3
4
9
樣例輸入 2
30 10
347297 7767863 4687361 4266761 1869189 6183125 6228737 7377798 2298221 253439 2279737 7603021 9596641 3461977 8857135 7648897 1264321 7381859 2257573 3750694 7066537 7631697 3115165 3367245 3742733 7943233 4901377 2381377 3162917 3567345
1 7 26 2298221
3 19 6712240
4 23 29 3743106
5 7 24 7624712
1 7 22 7066537
5 1 18 251894
2 19 21 1
5 15 16 8855774
2 1 12 10
3 15 3539397
樣例輸出 2
5
3742733
7631697
9
253439
3750694
8857135
7377798
提示
1.n和m的資料範圍:n,m<=50000
2.序列中每個數的資料範圍:[0,1e8]
3.雖然原題沒有,但事實上5操作的k可能為負數
題解
這道題很(休閒)煩。。但看題目就知道是樹套樹
對此主要有兩種思考方式。
可以用線段樹維護位置,平衡樹維護值。
操作一就比較簡單,用數棵線段樹組成對應區間,直接在平衡樹上查詢即可。
操作二就乏力了,二分答案操作一
操作三不說。
操作四、五,用數棵線段樹組成對應區間,查查前驅後繼即可。
此做法的問題在於,操作二可能會帶來較高的時間複雜度。
還有一種方法,用線段樹維護值,平衡樹維護位置
操作二可以變為線上段樹上二分值,用平衡樹查詢對應值域有多少個數在對應區間【l,r】中。
操作一變為查詢比x小的數中有多少個在區間【l,r】中。
操作三懶得講了。
操作四、五,找到在區間【l,r】有數的最小的大於x的值,或最大的小於x的值即可。
為了更快,可離散化
具體見程式碼。
程式碼
注:倆樹都打得賊爛,有一個會被T掉
1:線段樹維護位置,平衡樹維護值
#include <cstdio>
#include <iostream>
#include <cstdlib>
using namespace std;
const int Q=3000000;
int f[Q],ls[Q],rs[Q],si[Q],v[Q],cnt[Q],root[Q];
void lx(int x)
{
int y=f[x],z=f[y];
if(z)if(ls[z]==y)ls[z]=x;
else rs[z]=x;
f[x]=z;
rs[y]=ls[x];
f[rs[y]]=y;
ls[x]=y;
f[y]=x;
si[x]=si[y];
si[y]=si[ls[y]]+si[rs[y]]+cnt[y];
}
void rx(int x)
{
int y=f[x],z=f[y];
if(z)if(ls[z]==y)ls[z]=x;
else rs[z]=x;
f[x]=z;
ls[y]=rs[x];
f[ls[y]]=y;
rs[x]=y;
f[y]=x;
si[x]=si[y];
si[y]=si[ls[y]]+si[rs[y]]+cnt[y];
}
void splay(int x,int be)
{
while(f[x])
{
int y=f[x],z=f[y];
if(z)
if(ls[z]==y)
if(ls[y]==x)
rx(y),rx(x);
else lx(x),rx(x);
else if(rs[y]==x)
lx(y),lx(x);
else rx(x),lx(x);
else if(ls[y]==x)rx(x);
else lx(x);
}
root[be]=x;
}
int qian(int x,int be)
{
splay(x,be);
if(!ls[x])return -1;
x=ls[x];
while(rs[x])x=rs[x];
return v[x];
}
int hou(int x,int be)
{
splay(x,be);
if(!rs[x])return -1;
x=rs[x];
while(ls[x])x=ls[x];
return v[x];
}
void del(int x,int be)
{
splay(x,be);
if((--cnt[x])>0){
--si[x];
return;
}
int lls=ls[x],rrs=rs[x];
f[lls]=f[rrs]=ls[x]=si[x]=rs[x]=0;
if(!lls){
if(!rrs)root[be]=0;
else root[be]=rrs;
return;
}
root[be]=lls;
while(rs[lls])lls=rs[lls];
splay(lls,be);
rs[lls]=rrs;
f[rrs]=lls;
si[lls]+=si[rrs];
}
int Find(int y,int be)
{
int t=root[be];
while(t)
{
if(v[t]==y){
if(rand()&1)splay(t,be);return t;
}
if(y<v[t])t=ls[t];
else t=rs[t];
}
return -1;
}
int YWH=0;
int ins(int y,int be)
{
if(!root[be]){
root[be]=++YWH;
cnt[YWH]=si[YWH]=1;
f[YWH]=ls[YWH]=rs[YWH]=0;
v[YWH]=y;
return YWH;
}
int t=root[be];
while(t)
{
++si[t];
if(v[t]==y)
{++cnt[t];return t;}
if(y<v[t])
if(ls[t])t=ls[t];
else{ls[t]=++YWH;f[YWH]=t;break;}
else
if(rs[t])t=rs[t];
else{rs[t]=++YWH;f[YWH]=t;break;}
}
v[YWH]=y;
cnt[YWH]=si[YWH]=1;
ls[YWH]=rs[YWH]=0;
splay(YWH,be);
return YWH;
}
int lef[Q],rig[Q];
void add(int now,int l,int r,int x,int v)
{
ins(v,now);
if(l==r)return;
int mid=l+r >>1;
if(x<=mid)add(now<<1,l,mid,x,v);
else add((now<<1)|1,mid+1,r,x,v);
}
void fack(int now,int l,int r,int x,int v)
{
del(Find(v,now),now);
if(l==r)return;
int mid=l+r >>1;
if(x<=mid)fack(now<<1,l,mid,x,v);
else fack((now<<1)|1,mid+1,r,x,v);
}
int getrank(int now,int l,int r,int x,int y,int v)
{
if(x<=l&&y>=r){
int o=ins(v,now);
int p;
splay(o,now);
if(!ls[o])p=0;
else p=si[ls[o]];
del(o,now);
return p;
}
int temp=0,mid=l+r >>1;
if(x<=mid)temp+=getrank(now<<1,l,mid,x,y,v);
if(y>mid)temp+=getrank((now<<1)|1,mid+1,r,x,y,v);
return temp;
}
int before(int now,int l,int r,int x,int y,int v)
{
if(x<=l&&y>=r){
int o=ins(v,now);
int p=qian(o,now);
del(o,now);
if(p<0)p=-998244353;
return p;
}
int mid=l+r >>1,op=-998244353;
if(x<=mid)op=max(op,before(now<<1,l,mid,x,y,v));
if(y>mid)op=max(op,before((now<<1)|1,mid+1,r,x,y,v));
return op;
}
int after(int now,int l,int r,int x,int y,int v)
{
if(x<=l&&y>=r){
int o=ins(v,now);
int p=hou(o,now);
del(o,now);
if(p<0)p=998244353;
return p;
}
int mid=l+r >>1,op=998244353;
if(x<=mid)op=min(op,after(now<<1,l,mid,x,y,v));
if(y>mid)op=min(op,after((now<<1)|1,mid+1,r,x,y,v));
return op;
}
int a[50005];
int main()
{
int i,n,m,x,y,p;
scanf("%d%d",&n,&m);srand(n^m);
for(i=1;i<=n;i++)
scanf("%d",&a[i]),add(1,1,n,i,a[i]);
while(m--){
scanf("%d",&i);
switch(i){
case 1:{
scanf("%d%d%d",&x,&y,&p);
printf("%d\n",getrank(1,1,n,x,y,p)+1);
break;
}
case 2:{
scanf("%d%d%d",&x,&y,&p);
int L=0,R=100000000;
while(L<=R){
int mid=L+R>>1;
if(getrank(1,1,n,x,y,mid)>=p)R=mid-1;
else L=mid+1;
}
printf("%d\n",R);
break;
}
case 3:{
scanf("%d%d",&x,&y);
fack(1,1,n,x,a[x]);
a[x]=y;
add(1,1,n,x,a[x]);
break;
}
case 4:{
scanf("%d%d%d",&x,&y,&p);
printf("%d\n",before(1,1,n,x,y,p));
break;
}
case 5:{
scanf("%d%d%d",&x,&y,&p);
printf("%d\n",after(1,1,n,x,y,p));
break;
}
}
}
return 0;
}
2:線段樹維護值,平衡樹維護位置
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstdlib>
using namespace std;
const int Q=3000000;
int f[Q],ls[Q],rs[Q],si[Q],v[Q],cnt[Q],root[Q];
inline void lx(int x)
{
register int y=f[x],z=f[y];
if(z)if(ls[z]==y)ls[z]=x;
else rs[z]=x;
f[x]=z;
rs[y]=ls[x];
f[rs[y]]=y;
ls[x]=y;
f[y]=x;
si[x]=si[y];
si[y]=si[ls[y]]+si[rs[y]]+cnt[y];
}
inline void rx(int x)
{
register int y=f[x],z=f[y];
if(z)if(ls[z]==y)ls[z]=x;
else rs[z]=x;
f[x]=z;
ls[y]=rs[x];
f[ls[y]]=y;
rs[x]=y;
f[y]=x;
si[x]=si[y];
si[y]=si[ls[y]]+si[rs[y]]+cnt[y];
}
void splay(int x,int be)
{
while(f[x])
{
register int y=f[x],z=f[y];
if(z)
if(ls[z]==y)
if(ls[y]==x)
rx(y),rx(x);
else lx(x),rx(x);
else if(rs[y]==x)
lx(y),lx(x);
else rx(x),lx(x);
else if(ls[y]==x)rx(x);
else lx(x);
}
root[be]=x;
}
void del(int x,int be)
{
splay(x,be);
if((--cnt[x])>0){
--si[x];
return;
}
int lls=ls[x],rrs=rs[x];
f[lls]=f[rrs]=ls[x]=si[x]=rs[x]=0;
if(!lls){
if(!rrs)root[be]=0;
else root[be]=rrs;
return;
}
root[be]=lls;
while(rs[lls])lls=rs[lls];
splay(lls,be);
rs[lls]=rrs;
f[rrs]=lls;
si[lls]+=si[rrs];
}
int Find(int y,int be)
{
register int t=root[be];
while(t)
{
if(v[t]==y){
if(ls[t])
if(rand()&1)splay(ls[t],be);
return t;
}
if(y<v[t])t=ls[t];
else t=rs[t];
}
return -1;
}
int YWH=0;
int ins(int y,int be)
{
if(!root[be]){
root[be]=++YWH;
cnt[YWH]=si[YWH]=1;
v[YWH]=y;
return YWH;
}
int t=root[be];
while(t)
{
++si[t];
if(v[t]==y)
{++cnt[t];return t;}
if(y<v[t])
if(ls[t])t=ls[t];
else{ls[t]=++YWH;break;}
else
if(rs[t])t=rs[t];
else{rs[t]=++YWH;break;}
}
f[YWH]=t;
v[YWH]=y;
cnt[YWH]=si[YWH]=1;
ls[YWH]=rs[YWH]=0;
splay(YWH,be);
return YWH;
}
int lef[Q],rig[Q],qw=1;
void add(int now,int l,int r,int x,int v)
{
ins(x,now);
if(l==r)return;
int mid=l+r >>1;
if(v<=mid){
if(!lef[now])lef[now]=++qw;
add(lef[now],l,mid,x,v);
}
else{
if(!rig[now])rig[now]=++qw;
add(rig[now],mid+1,r,x,v);
}
}
void fack(int now,int l,int r,int x,int v)
{
del(Find(x,now),now);
if(l==r)return;
int mid=l+r >>1;
if(v<=mid)
fack(lef[now],l,mid,x,v);
else
fack(rig[now],mid+1,r,x,v);
}
int get(int x,int be)
{
if(be==0)return 0;
int o=ins(x,be);
splay(o,be);
int ans=si[ls[o]];
del(o,be);
return ans;
}
int p1(int now,int l,int r,int x,int y,int v)
{
if(v>=r)
return get(y+1,now)-get(x,now);
int mid=l+r >>1,temp=0;
if(!lef[now])lef[now]=++qw;
temp+=p1(lef[now],l,mid,x,y,v);
if(v>mid){
if(!rig[now])rig[now]=++qw;
temp+=p1(rig[now],mid+1,r,x,y,v);
}
return temp;
}
int p2(int now,int l,int r,int x,int y,int v)
{
if(l==r)return l;
int mid=l+r >>1;
int be=lef[now],omg=get(y+1,be)-get(x,be);
if(omg>=v)return p2(lef[now],l,mid,x,y,v);
return p2(rig[now],mid+1,r,x,y,v-omg);
}
int p4(int now,int l,int r,int x,int y,int v)
{
if((!now)||l>v||get(y+1,now)-get(x,now)==0)return -11;
if(l==r)return l;
int mid=l+r >>1;
int t=p4(rig[now],mid+1,r,x,y,v);
if(t>0)return t;
return p4(lef[now],l,mid,x,y,v);
}
int p5(int now,int l,int r,int x,int y,int v)
{
if((!now)||r<v||get(y+1,now)-get(x,now)==0)return 998244353;
if(l==r)return l;
int mid=l+r >>1;
int t=p5(lef[now],l,mid,x,y,v);
if(t<998244353)return t;
return p5(rig[now],mid+1,r,x,y,v);
}
int a[50005];
int query[50005][5];
int omg[600000],inc;
int main()
{
int i,n,m,x,y,p;
scanf("%d%d",&n,&m);
srand(n+m-1);
for(i=1;i<=n;i++)
scanf("%d",&a[i]),omg[++inc]=a[i];
for(i=1;i<=m;i++){
scanf("%d%d%d",&query[i][0],&query[i][1],&query[i][2]);
if(query[i][0]!=3)scanf("%d",&query[i][3]);
if(query[i][0]==1||query[i][0]==4||query[i][0]==5)omg[++inc]=query[i][3];
else if(query[i][0]==3)omg[++inc]=query[i][2];
}
sort(omg+1,omg+inc+1);
int ofo=unique(omg+1,omg+inc+1)-omg-1;
for(i=1;i<=n;i++)
a[i]=lower_bound(omg+1,omg+ofo+1,a[i])-omg,add(1,1,ofo,i,a[i]);
for(int j=1;j<=m;j++){
i=query[j][0];
switch(i){
case 1:{
x=query[j][1];
y=query[j][2];
p=query[j][3];
p=lower_bound(omg+1,omg+ofo+1,p)-omg;
printf("%d\n",p1(1,1,ofo,x,y,p-1)+1);
break;
}
case 2:{
x=query[j][1];
y=query[j][2];
p=query[j][3];
printf("%d\n",omg[p2(1,1,ofo,x,y,p)]);
break;
}
case 3:{
x=query[j][1];
y=query[j][2];
y=lower_bound(omg+1,omg+ofo+1,y)-omg;
fack(1,1,ofo,x,a[x]);
a[x]=y;
add(1,1,ofo,x,a[x]);
break;
}
case 4:{
x=query[j][1];
y=query[j][2];
p=query[j][3];
p=lower_bound(omg+1,omg+ofo+1,p)-omg;
printf("%d\n",omg[p4(1,1,ofo,x,y,p-1)]);
break;
}
case 5:{
x=query[j][1];
y=query[j][2];
p=query[j][3];
p=lower_bound(omg+1,omg+ofo+1,p)-omg;
printf("%d\n",omg[p5(1,1,ofo,x,y,p+1)]);
break;
}
}
}
return 0;
}