1. 程式人生 > >ZQC 的手辦---------------線段樹+堆

ZQC 的手辦---------------線段樹+堆

bubuko 依賴 fff lose == har targe 快速 bsp

技術分享圖片

技術分享圖片


  看到題目基本上都會想到線段樹維護吧。

    但是詢問看似比較棘手,其實題目相當於就相當於在要求在詢問的時候需要準確的,依次的算出答案。難道不是嗎?

    在確定用線段樹維護修改操作後,這是一種怎樣的詢問呢?-------------求一段區間的前 k 小的數,而且我們不能依賴區間長度!

    然後,我們考慮在取出一個區間的最小值之後會產生什麽:區間分裂了,總數減少了,有一個最值被確定了。這樣一來,接下來的答

     案就在剩下的區間裏面了。

  •

可以發現只要我們對一個區間保存一個最值得話,這樣的操作就可以持續下去了。因為我們每次保存了一堆區間與對應的區間最值,

     那麽接下來的答案就必定是這些區間最值中的最值。快速查詢最值就可以用上堆了。

技術分享圖片
  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 int n,m,opt,x,y,a,b;
  4 int f[2000050][2];
  5 int t[10000050],top;
  6 int va,vb,pa,pb,tl,tr,now;
  7 int read()
  8 {
  9     int
x=0; 10 char ch=getchar(); 11 while(ch<0||ch>9) 12 ch=getchar(); 13 while(ch>=0&&ch<=9) 14 { 15 x=x*10+ch-48; 16 ch=getchar(); 17 } 18 return x; 19 } 20 struct node 21 { 22 int l,r,v,pos; 23 bool
operator<(const node & p)const 24 { 25 return v>p.v; 26 } 27 }pr; 28 void build(int u,int l,int r) 29 { 30 if(l==r) 31 { 32 scanf("%d",&f[u][0]); 33 f[u][1]=l; 34 return ; 35 } 36 int mid=(l+r)>>1; 37 build(u<<1,l,mid); 38 build(u<<1|1,mid+1,r); 39 if(f[u<<1][0]<f[u<<1|1][0]) 40 { 41 f[u][0]=f[u<<1][0]; 42 f[u][1]=f[u<<1][1]; 43 } 44 else 45 { 46 f[u][0]=f[u<<1|1][0]; 47 f[u][1]=f[u<<1|1][1]; 48 } 49 } 50 void update(int u,int l,int r) 51 { 52 f[u<<1][0]=max(f[u<<1][0],f[u][0]); 53 f[u<<1|1][0]=max(f[u<<1|1][0],f[u][0]); 54 } 55 void change(int u,int l,int r) 56 { 57 if(x<=l&&r<=y) 58 { 59 f[u][0]=max(f[u][0],a); 60 return ; 61 } 62 int mid=(l+r)>>1;update(u,l,r); 63 if(x<=mid) 64 change(u<<1,l,mid); 65 if(y>mid) 66 change(u<<1|1,mid+1,r); 67 if(f[u<<1][0]<f[u<<1|1][0]) 68 { 69 f[u][0]=f[u<<1][0]; 70 f[u][1]=f[u<<1][1]; 71 } 72 else 73 { 74 f[u][0]=f[u<<1|1][0]; 75 f[u][1]=f[u<<1|1][1]; 76 } 77 } 78 void calc(int u,int l,int r,int x,int y,int &val,int &pos) 79 { 80 if(x<=l&&r<=y) 81 { 82 if(val>f[u][0]) 83 { 84 val=f[u][0]; 85 pos=f[u][1]; 86 } 87 return ; 88 } 89 update(u,l,r); 90 int mid=(l+r)>>1; 91 if(x<=mid) 92 calc(u<<1,l,mid,x,y,val,pos); 93 if(y>mid) 94 calc(u<<1|1,mid+1,r,x,y,val,pos); 95 } 96 int main() 97 { 98 n=read(); 99 build(1,1,n); 100 m=read(); 101 while(m--) 102 { 103 opt=read(); 104 x=read(); 105 y=read(); 106 a=read(); 107 if(opt==1) 108 change(1,1,n); 109 else 110 { 111 b=read();top=0; 112 priority_queue<node >q; 113 va=0x7fffffff,vb=0x7fffffff; 114 calc(1,1,n,x,y,va,pa); 115 q.push(node{x,y,va,pa}); 116 while(!q.empty()&&top<b) 117 { 118 tl=q.top().l; 119 tr=q.top().r; 120 now=q.top().pos; 121 if(q.top().v>=a) 122 break; 123 t[++top]=q.top().v; 124 q.pop(); 125 va=vb=0x7fffffff; 126 if(now>tl) 127 { 128 calc(1,1,n,tl,now-1,va,pa); 129 q.push(node{tl,now-1,va,pa}); 130 } 131 if(now<tr) 132 { 133 calc(1,1,n,now+1,tr,vb,pb); 134 q.push(node{now+1,tr,vb,pb}); 135 } 136 } 137 if(top<b) 138 printf("-1\n"); 139 else 140 { 141 for(int i=1;i<=b;++i) 142 printf("%d ",t[i]); 143 printf("\n"); 144 } 145 } 146 } 147 return 0; 148 }
代碼

此題的堆操作有一道模板題

https://www.luogu.org/problemnew/show/P2048

ZQC 的手辦---------------線段樹+堆