题目链接
题目大意:
给定一个长度为n的数列,有m次询问,询问形如l r k
要你在区间[l,r]内选一个长度为k的区间,求区间最小数的最大值
题解
做这种题有套路:
(1)最小值最大化,且具有单调性 ——> 整体二分的思路
(2)根据二分答案,所选数为 x 时,大于 x 的贡献为1,反之为0
(3)要使连续的区间都大于等于 x (也是所选的最小数),且长度至少为k,就等同于 在查询区间内找长度至少为k的连续 1 的子区间。——> 线段树合并的套路
(4)对每种情况建线段树不现实,可以发现,一个数与它刚小一点的数只有一个位置要修改——>主席树,单点修改
线段树合并就是加两个变量:最左/右连续 1 的长度
二分后,分大于小于后,贡献为1与0,其实在其它题,贡献会是1与-1,具体情况具体分析。
我写了两种写法,一个结构体,一个没用结构体
ps:写三目运算符一定要加括号(一开始我就错这里,w了好几发才发现的)
代码一:t[i].ls=t[l].ls+((t[l].ls==(len-len/2))?t[r].ls:0);
代码二:t[i].ls=t[l].ls+(t[l].ls==(len-len/2))?t[r].ls:0;
这两串代码意思完全不同,代码一的条件是(t[l].ls==(len-len/2)
。代码二的条件是t[l].ls+(t[l].ls==(len-len/2))
,代码二中t[l].ls
就不会单独加进去了。
还有,左区间的区间长度要比右区间的大,所以左区间是len-len/2
,不要写反
const int maxn=2e5+7;
int n,q,tot,rt[maxn];
typedef pair<int,int>pi;
pi a[maxn];
bool cmp(pi x,pi y){ return x.first>y.first; }
struct node{
int l,r,ls,rs,sum;
node(){ ls=rs=l=r=sum=0; }
}t[maxn<<5];
void pushup(int i,int len){
int l=t[i].l,r=t[i].r;
t[i].ls=t[l].ls+((t[l].ls==(len-len/2))?t[r].ls:0);
t[i].rs=t[r].rs+((t[r].rs==(len/2))?t[l].rs:0);
t[i].sum=max(max(t[l].sum,t[r].sum),t[l].rs+t[r].ls);
}
void update(int &i,int pre,int l,int r,int id){
i=++tot; t[i].l=t[pre].l; t[i].r=t[pre].r;
if(l==r){
t[i].ls=t[i].rs=t[i].sum=1;
return;
}
int mid=l+r>>1;
if(id<=mid) update(t[i].l,t[pre].l,l,mid,id);
else update(t[i].r,t[pre].r,mid+1,r,id);
pushup(i,r-l+1);
}
node query(int i,int l,int r,int x,int y){
if(x<=l&&r<=y) return t[i];
int mid=l+r>>1,len=r-l+1;
node L,R,ans;
if(x<=mid) L=query(t[i].l,l,mid,x,y);
if(y>mid) R=query(t[i].r,mid+1,r,x,y);
ans.ls=L.ls+((L.ls==len-len/2)?R.ls:0);
ans.rs=R.rs+((R.rs==len/2)?L.rs:0);
ans.sum=max(max(L.sum,R.sum),L.rs+R.ls);
return ans;
}
int main(){
n=read();
for(int i=1;i<=n;i++){
a[i].first=read();
a[i].second=i;
}
sort(a+1,a+1+n,cmp);
for(int i=1;i<=n;i++) update(rt[i],rt[i-1],1,n,a[i].second);
q=read();
while(q--){
int x,y,k,l,r;
x=read(); y=read(); k=read();
l=1; r=n;
while(l<r){
int mid=l+r>>1;
if(query(rt[mid],1,n,x,y).sum>=k) r=mid;
else l=mid+1;
}
printf("%d\n",a[l].first);
}
}
写法二
const int maxn=2e5+7;
typedef pair<int,int>pi;
int n,m,cnt;
int rt[maxn],tot,ls[maxn<<5],rs[maxn<<5],sum[maxn<<5];
int p[maxn<<5],q[maxn<<5];
pi a[maxn];
typedef struct node{
int s,p,q;
node(){ s=p=q=0; }
}sz;
bool cmp(pi x,pi y){ return x.first>y.first; }
void pushup(int i,int len){
p[i]=p[ls[i]]+((p[ls[i]]==len-len/2)?p[rs[i]]:0);
q[i]=q[rs[i]]+((q[rs[i]]==len/2)?q[ls[i]]:0);
sum[i]=max(max(sum[ls[i]],sum[rs[i]]),q[ls[i]]+p[rs[i]]);
}
void update(int &i,int pre,int l,int r,int id){
if(id>r||id<l) return;
i=++tot; ls[i]=ls[pre]; rs[i]=rs[pre];
if(l==r){
p[i]=q[i]=sum[i]=1;
return;
}
int mid=l+r>>1;
update(ls[i],ls[pre],l,mid,id); update(rs[i],rs[pre],mid+1,r,id);
pushup(i,r-l+1);
}
sz query(int i,int l,int r,int x,int y){
sz t;
if(r<x||l>y) return t;
t.s=sum[i]; t.p=p[i]; t.q=q[i];
if(x<=l&&r<=y) return t;
int mid=l+r>>1,len=r-l+1;
sz L,R,ans;
L=query(ls[i],l,mid,x,y);
R=query(rs[i],mid+1,r,x,y);
ans.p=L.p+((L.p==len-len/2)?R.p:0);
ans.q=R.q+((R.q==len/2)?L.q:0);
ans.s=max(max(L.s,R.s),L.q+R.p);
return ans;
}
int main(){
n=read();
for(int i=1;i<=n;i++){
a[i].first=read();
a[i].second=i;
}
sort(a+1,a+1+n,cmp);
for(int i=1;i<=n;i++) update(rt[i],rt[i-1],1,n,a[i].second);
m=read();
while(m--){
int x=read(),y=read(),k=read(),l=1,r=n;
while(l<r){
int mid=l+r>>1;
if(query(rt[mid],1,n,x,y).s>=k) r=mid;
else l=mid+1;
}
printf("%d\n",a[l].first);
}
}