ZQC 的手办---------------线段树+堆
• 看到题目基本上都会想到线段树维护吧。
• 但是询问看似比较棘手,其实题目相当于就相当于在要求在询问的时候需要准确的,依次的算出答案。难道不是吗?
• 在确定用线段树维护修改操作后,这是一种怎样的询问呢?-------------求一段区间的前 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 }
此题的堆操作有一道模板题