题意:

给定一个长度为n的序列a[i]。给定m次询问。

每次查询为l,r,w,表示在区间l,r中,问对于连续的长为w的一段中最小的数字的最大值是多少。

题解:

先把所有元素按高度从大到小排序,以高度为时间轴,元素编号为下标建立可持久化线段树。

那么,第i棵线段树只会保存高度大于等于i的元素下标情况。

对于每个询问,二分答案,在当前二分答案的线段树中找区间l r内最长的连续线段,这里涉及区间合并,是之前从来没有接触过的知识点。

这道题无论是建树方法还是线段树信息的维护都是从没接触过的,需要好好复习。



#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+100;
const int M=maxn*40;
int a[maxn],n,q,T[maxn];
int tot=1;
vector<pair<int,int> > z;
struct node {
int l,r;
int len,maxLen,pre,suf;
//len表示每个节点代表的区间长度
//maxLen表示每个节点内部最长的连续区间的长度
//pre表示每个节点代表的区间的最大前缀
//suf表示每个节点代表的区间的最大后缀
}segTree[M];//可持久化线段树结构体
bool cmp (pair<int,int> x,pair<int,int> y) {
return x.first>y.first;//先按高度从大到小排序
}
void push_up (int i) {
if (segTree[segTree[i].l].len==segTree[segTree[i].l].pre) {
segTree[i].pre=segTree[segTree[i].l].len+segTree[segTree[i].r].pre;
}
else {
segTree[i].pre=segTree[segTree[i].l].pre;
}

if (segTree[segTree[i].r].len==segTree[segTree[i].r].suf) {
segTree[i].suf=segTree[segTree[i].r].len+segTree[segTree[i].l].suf;
}
else {
segTree[i].suf=segTree[segTree[i].r].suf;
}

segTree[i].maxLen=max(segTree[i].pre,segTree[i].suf);
segTree[i].maxLen=max(segTree[i].maxLen,segTree[segTree[i].l].suf+segTree[segTree[i].r].pre);
segTree[i].maxLen=max(segTree[i].maxLen,max(segTree[segTree[i].l].maxLen,segTree[segTree[i].r].maxLen));
}

void up (int &root,int lst,int l,int r,int p) {
root=tot++;
segTree[root]=segTree[lst];
segTree[root].len=r-l+1;
segTree[lst].len=r-l+1;
if (l==r) {
segTree[root].maxLen=1;
segTree[root].pre=segTree[root].suf=1;
return;
}
int mid=(l+r)>>1;
if (p<=mid)
up(segTree[root].l,segTree[lst].l,l,mid,p);
else
up(segTree[root].r,segTree[lst].r,mid+1,r,p);
push_up(root);
}

node merge (node x,node y) {
node ans;
if (x.len==0) return y;
if (x.len==x.pre) {
ans.pre=x.len+y.pre;
}
else {
ans.pre=x.pre;
}

if (y.suf==y.len) {
ans.suf=y.len+x.suf;
}
else {
ans.suf=y.suf;
}

ans.len=x.len+y.len;
ans.maxLen=max(ans.suf,ans.pre);
ans.maxLen=max(ans.maxLen,x.suf+y.pre);
ans.maxLen=max(ans.maxLen,max(x.maxLen,y.maxLen));
return ans;
}

node query (int root,int l,int r,int L,int R) {
if (l>=L&&r<=R) {
return segTree[root];
}
node ans;
ans.l=ans.len=ans.pre=ans.suf=ans.r=ans.maxLen=0;
int mid=(l+r)>>1;
if (L<=mid) ans=merge(ans,query(segTree[root].l,l,mid,L,R));
if (R>mid) ans=merge(ans,query(segTree[root].r,mid+1,r,L,R));
return ans;
}

int main () {
scanf("%d",&n);
for (int i=1;i<=n;i++) {
scanf("%d",a+i);
z.push_back(make_pair(a[i],i));
}
sort(z.begin(),z.end(),cmp);
for (int i=0;i<n;i++) up(T[i+1],T[i],1,n,z[i].second);//以高度为轴,编号为下标建立线段树
scanf("%d",&q);
while (q--) {
int ql,qr,w;
scanf("%d%d%d",&ql,&qr,&w);
int l=1,r=n,ans=0;
while (l<=r) {
int mid=(l+r)>>1;
if (query(T[mid],1,n,ql,qr).maxLen>=w) {
ans=mid;
r=mid-1;
}
else {
l=mid+1;
}
}
//printf("%d\n",ans);
printf("%d\n",z[ans-1].first);
}
}