1. 程式人生 > >求最值背景下動態刪除線段樹節點

求最值背景下動態刪除線段樹節點

int scan 輸入 包含 mes else 兩個 let del

動態最值(minmax.Cpp/c/Java)
(空間限制128M)

有一個包含n個元素的數組,要求實現以下操作:
DELETE k:刪除位置k上的數。右邊的數往左移一個位置。
QUERY i j:查詢位置i~j上所有數的最小值和最大值。

【輸入】(minmax.in)
輸入第一行包含兩個數n, m,表示原始數組的元素個數和操作的個數。第二行包括n個數,表示原始數組。以下m行,每行格式為1 k或者2 i j,其中第一個數為1表示刪除操作,為2表示詢問操作。
【輸出】(minmax.out)
輸出一行,包括兩個數,表示該範圍內的最小值和最大值。
【樣例輸入】
10 4
1 5 2 6 7 4 9 3 1 5
2 2 8
1 3
1 6
2 2 8
【樣例輸出】
2 9
1 7
【限制】
數組中的元素絕對值均不超過109
第一組:n = 10, 1 分, 時限 0.1s
第二組:n = 333, 2 分, 時限 0.1s
第三組:n = 4232,3分, 時限 0.1s
第四組:n = 6324, 4分, 時限 0.2s
第五組:n = 9999, 5分, 時限 2s
第六組:n = 100000, m = 300000, 10分,時限 2s
第七組:n = 300000, m = 422342, 13分,時限 3s
第八組:n = 500000, m = 651222, 18分,時限 3s
第九組:n = 900000, m = 432122, 22分,時限 5s
第十組:n = 999999,m = 999999,22分,時限 5s

刪完後左移,我們並不是真的左移,而是線段樹節點記錄一個num,記錄子節點個數,根據這個遞歸地找刪除後的index

還沒對拍的標程如下,(樣例可過

 1 #include <stdio.h>
 2 #include <algorithm>
 3 using  namespace std;
 4 
 5 const int maxn=1e5+7;
 6 const int INF=1e9+7;
 7 int mi[maxn],mx[maxn],num[maxn],ls[maxn],rs[maxn],a[maxn],tot,n,m;
 8 void pup(int p){
9 mi[p]=min(mi[ls[p]],mi[rs[p]]); 10 mx[p]=max(mx[ls[p]],mx[rs[p]]); 11 num[p]=num[ls[p]]+num[rs[p]]; 12 } 13 void build(int p,int l,int r){ 14 if(l==r){mi[p]=mx[p]=a[l];num[p]=1;return ;}//index is p not l 15 int mid=(l+r)>>1; 16 build(ls[p]=++tot,l,mid); 17 build(rs[p]=++tot,mid+1
,r); 18 pup(p); 19 } 20 int cnt=0; 21 int queryMx(int p,int l,int r,int L,int R){ 22 if(l>=r&&r<=R){ //這裏不要寫反 23 return mx[p]; 24 } 25 if(L<=num[ls[p]]&&R>num[ls[p]]){ 26 return max(queryMx(ls[p],1,num[ls[p]],L,num[ls[p]]),queryMx(rs[p],1,num[rs[p]],1,R-num[ls[p]])); 27 } 28 else if(L<=num[ls[p]]){ 29 return queryMx(ls[p],1,num[ls[p]],L,R); 30 } 31 else{ 32 return queryMx(rs[p],1,num[rs[p]],L-num[ls[p]],R-num[ls[p]]); 33 } 34 } 35 int queryMi(int p,int l,int r,int L,int R){ 36 if(l>=L&&r<=R){ 37 return mi[p]; 38 } 39 if(L<=num[ls[p]]&&R>num[ls[p]]){ 40 return min(queryMi(ls[p],1,num[ls[p]],L,num[ls[p]]),queryMi(rs[p],1,num[rs[p]],1,R-num[ls[p]])); 41 } 42 else if(L<=num[ls[p]]){ 43 return queryMi(ls[p],1,num[ls[p]],L,R); 44 } 45 else{ 46 return queryMi(rs[p],1,num[rs[p]],L-num[ls[p]],R-num[ls[p]]); 47 } 48 } 49 void Delete(int p,int l,int r,int x){ 50 if(l==r){ 51 mi[p]=INF; 52 mx[p]=-INF; 53 num[p]=0; 54 return ; 55 } 56 if(x<=num[ls[p]]) Delete(ls[p],1,num[ls[p]],x); 57 else Delete(rs[p],1,num[rs[p]],x-num[ls[p]]); //由於刪除後所有數都向左移動,所以我們也得遞歸找位置刪除 58 pup(p); 59 } 60 int main(){ 61 scanf("%d%d",&n,&m); 62 for(int i=1;i<=n;++i) scanf("%d",a+i); 63 int op,l,r,x; 64 tot=1;build(1,1,n); 65 for(int i=1;i<=m;++i){ 66 scanf("%d",&op); 67 if(op==1){ 68 scanf("%d",&x); 69 Delete(1,1,num[1],x); 70 } 71 else{ 72 scanf("%d%d",&l,&r); 73 printf("%d %d\n",queryMi(1,1,num[1],l,r),queryMx(1,1,num[1],l,r)); 74 } 75 } 76 return 0; 77 }

求最值背景下動態刪除線段樹節點