大概题意:
给一数组a,问在某一区间L~R中,问对于连续的长为W的一段中最小的数字的最大值是多少.
显然可以转化成二分高度然后判断可行性的问题.
考虑到高度肯定为数组中的某一个值,将数组从大到小排序. 建n棵线段树,对于第 i 棵线段树,将 大于等于a[i] 的叶子的值设置为1,其他的叶子设置为0,问题就转化成了用线段树求某一区间中最长的连续的1的个数,这是一个线段树的经典问题,可以通过维护每个节点的 左边连续和,右边连续和,连续和的最大值 得到.
由于空间问题,不可能建立10^5棵线段树,考虑到相邻的两个线段树之间只有一条边的值是不一样的,可以共用其他节点来节省空间,所以建立一个可持久化线段树就可以了, 具体细节可以看代码 .
/* ***********************************************
Author :CKboss
Created Time :2015年03月11日 星期三 19时18分54秒
File Name :CF484E_2.cpp
************************************************ */
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
#include <cmath>
#include <cstdlib>
#include <vector>
#include <queue>
#include <set>
#include <map>
using namespace std;
const int maxn=100100;
const int maxm=maxn*40;
int n;
int ch[maxm][2],leftsum[maxm],rightsum[maxm],allsum[maxm],lenth[maxm];
int T[maxn],tot,res,toleft;
struct Fe
{
int h,id;
}fe[maxn];
bool cmp(Fe a,Fe b)
{
return a.h>b.h;
}
/// push_up
void push_up(int rt)
{
lenth[rt]=lenth[ch[rt][0]]+lenth[ch[rt][1]];
leftsum[rt]=leftsum[ch[rt][0]];
if(leftsum[ch[rt][0]]==lenth[ch[rt][0]])
leftsum[rt]+=leftsum[ch[rt][1]];
rightsum[rt]=rightsum[ch[rt][1]];
if(rightsum[ch[rt][1]]==lenth[ch[rt][1]])
rightsum[rt]+=rightsum[ch[rt][0]];
allsum[rt]=max(allsum[ch[rt][0]],allsum[ch[rt][1]]);
allsum[rt]=max(allsum[rt],rightsum[ch[rt][0]]+leftsum[ch[rt][1]]);
}
/// build
int build(int l,int r)
{
int rt=tot++;
if(l==r)
{
leftsum[rt]=rightsum[rt]=allsum[rt]=0;
lenth[rt]=1;
return rt;
}
int m=(l+r)/2;
ch[rt][0]=build(l,m);
ch[rt][1]=build(m+1,r);
push_up(rt);
return rt;
}
/// insert
int insert(int oldrt,int pos,int l,int r)
{
int rt=tot++;
ch[rt][0]=ch[oldrt][0];
ch[rt][1]=ch[oldrt][1];
if(l==pos&&r==pos)
{
leftsum[rt]=rightsum[rt]=allsum[rt]=1;
lenth[rt]=1;
return rt;
}
int m=(l+r)/2;
if(pos<=m) ch[rt][0]=insert(ch[oldrt][0],pos,l,m);
else ch[rt][1]=insert(ch[oldrt][1],pos,m+1,r);
push_up(rt);
return rt;
}
/// query
void query(int rt,int L,int R,int l,int r)
{
if(L<=l&&r<=R)
{
res=max(res,allsum[rt]);
toleft+=leftsum[rt];
res=max(res,toleft);
if(leftsum[rt]!=lenth[rt])
toleft=rightsum[rt];
res=max(res,toleft);
return ;
}
int m=(l+r)/2;
if(R<=m) return query(ch[rt][0],L,R,l,m);
else if(L>m) return query(ch[rt][1],L,R,m+1,r);
else
{
query(ch[rt][0],L,R,l,m);
query(ch[rt][1],L,R,m+1,r);
}
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
int x;
scanf("%d",&x);
fe[i].h=x; fe[i].id=i;
}
sort(fe+1,fe+1+n,cmp);
T[0]=build(1,n);
for(int i=1;i<=n;i++)
T[i]=insert(T[i-1],fe[i].id,1,n);
int T_T;
scanf("%d",&T_T);
while(T_T--)
{
int L,R,W;
scanf("%d%d%d",&L,&R,&W);
int low=1,high=n,ans;
while(low<=high)
{
int mid=(low+high)/2;
toleft=res=0;
query(T[mid],L,R,1,n);
if(res>=W)
{
ans=mid; high=mid-1;
}
else low=mid+1;
}
printf("%d\n",fe[ans].h);
}
return 0;
}