【題目描述】
寫一種資料結構,來維護乙個有序數列,其中需要提供以下操作:
1.查詢k在區間內的排名
2.查詢區間內排名為k的值
3.修改某一位值上的數值
4.查詢k在區間內的前驅(前驅定義為小於x,且最大的數)
5.查詢k在區間內的後繼(後繼定義為大於x,且最小的數)
【輸入格式】
第一行兩個數n,m( n,m <= 50000 )表示長度為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的前驅(沒有前驅輸出no)
若opt=5 則為操作5,之後有三個數l,r,k 表示查詢區間[l,r]內k的後繼(沒有後繼輸出no)
【輸出格式】
對於操作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 output24
349hint:
1、序列中每個數的資料範圍:[0,1e8]
2、雖然原題沒有,但事實上5操作的k可能為負數
這題我在bzoj上ac,在tvoj上最後兩個點tle(然而並不知道怎麼優化)。
昨天中午打了乙個中午,晚上調了乙個鐘,今天早上又調了兩個鐘。。呵呵。。
我的做法是在開一棵1~n的線段樹t,每個節點(管理t[x].l~t[x].r)開一棵treap,把t[x].l~t[x].r的值全部放進去。為了防止找前驅後繼的時候有問題,每棵treap上先放-inf和inf進去。
1.表示查詢k在區間[l,r]的排名:用線段樹找到[l,r]所需要用到的線段樹上的節點,開乙個陣列存起來,然後乙個個區間查詢比k小的數的個數。
2.表示查詢區間[l,r]內排名為k的數:mn和mx存下出現過的最小和最大的數是什麼。二分乙個數x,然後用1的方法看x的排名。
這裡注意乙個問題:找的是排名<=k的最大的數。
例如:1 2 3 3 3 5,查詢3的排名是3,但是如果我們要找排名為4的數,答案依然是3。
3.單點修改:順著線段樹走下去,中途所經過的點,都要在它那棵treap上del原來的數,ins新數
5.找後繼:同上。
1 #include2 #include3 #include4 #include5using
namespace
std;67
const
int n=50010,tn=50000*16+100,inf=(int
)1e9;
8struct
tr_nodec[2*tn];
11struct
xd_nodet[2*2*n];
14int
tl,cl,sl;
15int w[2*n],s[2*n];
1617
void updata(int
x)18
2324
void add(int d,int
f)25
3435
int find_ip(int d,int
id)36
45else
4650}51
return
x;52}53
54void rotate(int
x)55
7475
void splay(int x,int rt,int
id)7686}
87if(rt==0) t[id].root=x;88}
8990
void ins(int d,int
id)91
94int x=find_ip(d,id);
95if(c[x].d==d) c[x].n++;
96else
add(d,x);
97updata(x);
98 splay(x,0
,id);99}
100101
int build_xd_tree(int l,int
r)102
115else ins(-inf,x),ins(inf,x),ins(w[t[x].l],x);//
l==r
116return
x;117
}118
119void find_xd_id(int x,int l,int
r)120
122int lc=t[x].lc,rc=t[x].rc,mid=(t[x].l+t[x].r)>>1
;123
if(r<=mid) find_xd_id(lc,l,r);
124else
if(l>mid) find_xd_id(rc,l,r);
125else find_xd_id(lc,l,mid),find_xd_id(rc,mid+1
,r);
126}
127128
int find_qq(int d,int
id)129
136if(c[x].d>=d) x=0
;137
return
x;138
}139
140int find_hj(int d,int
id)141
148if(c[x].d<=d) x=0
;149
return
x;150
}151
152void del(int d,int
id)153
156int x0=find_qq(d,id);
157int x1=find_hj(d,id);
158 splay(x0,0
,id);
159splay(x1,x0,id);
160 c[x1].son[0]=0
;161
updata(x1);
162}
163164
void change(int x,int p,int
d)165
171int lc=t[x].lc,rc=t[x].rc,mid=(t[x].l+t[x].r)>>1
;172
if(p<=mid) change(lc,p,d);
173else
change(rc,p,d);
174del(w[p],x);ins(d,x);
175}
176177
int find_rk(int d,int id)//
the number of all that 178
184185
int opt1(int k,int l,int
r)186
193194
int minn(int x,int y)
195int maxx(int x,int y)
196197
int find_rank(int
k)198
204205
intmain()
206219 build_xd_tree(1
,n);
220for(int i=1;i<=m;i++)
221232
if(opt==2
)233
243 printf("
%d\n
",ll);
244}
245if(opt==3
)246
252if(opt==4
)253
260if(opt==5
)261
268}
269return0;
270 }
bzoj3196 二逼平衡樹(線段樹 splay)
您需要寫一種資料結構 可參考題目標題 來維護乙個有序數列,其中需要提供以下操作 1.查詢k在區間內的排名 2.查詢區間內排名為k的值 3.修改某一位值上的數值 4.查詢k在區間內的前驅 前驅定義為小於x,且最大的數 5.查詢k在區間內的後繼 後繼定義為大於x,且最小的數 第一行兩個數 n,m 表示長...
BZOJ3196 二逼平衡樹 線段樹套Splay
您需要寫一種資料結構 可參考題目標題 來維護乙個有序數列,其中需要提供以下操作 1.查詢k在區間內的排名 2.查詢區間內排名為k的值 3.修改某一位值上的數值 4.查詢k在區間內的前驅 前驅定義為小於x,且最大的數 5.查詢k在區間內的後繼 後繼定義為大於x,且最小的數 第一行兩個數 n,m 表示長...
Bzoj3196 二逼平衡樹
您需要寫一種資料結構 可參考題目標題 來維護乙個有序數列,其中需要提供以下操作 1.查詢k在區間內的排名 2.查詢區間內排名為k的值 3.修改某一位值上的數值 4.查詢k在區間內的前驅 前驅定義為小於x,且最大的數 5.查詢k在區間內的後繼 後繼定義為大於x,且最小的數 額,這個題,看了一眼就知道是...