CF484E. Sign on Fence
CF484E. Sign on Fence
题目大意
给你n块木板,每块木板有高度Hi,q次询问每次询问在[l,r]区间中最大的长度为w的区间的最小值。
思路
将木板从大到小排序,建动态开点线段树维护区间最长子段,于是就可以二分高度,判断这个高度在[l,r]
区间中存不存在长度大等于w的子段。
代码
#include
using namespace std;
#define dd(x) cout<<#x<<" = "< vi;
typedef pair pi;
bool cmp(const pi&a,const pi&b){return a.fi>b.fi;}
pi a[maxn];
int n,q,cnt, T[maxn];
struct node {
int ls,rs,l,r,s;
node (){ls=rs=l=r=s=0;}
}t[maxn<<5];
void push_up(int rt,int m){
int ls=t[rt].ls, rs = t[rt].rs;
int rm = m>>1, lm = m-rm;
t[rt].l = t[ls].l;
if(t[ls].l == lm) t[rt].l += t[rs].l;
t[rt].r = t[rs].r;
if(t[rs].r == rm) t[rt].r += t[ls].r;
t[rt].s = max(t[rs].l+t[ls].r,max(t[rs].s,t[ls].s));
return ;
}
void update(int pre,int &now,int pos,int l,int r){
now = ++cnt;
if(l==r){
t[now].l = t[now].r = t[now].s = 1;
return ;
}
t[now].ls = t[pre].ls;
t[now].rs = t[pre].rs;
int mid = l+r>>1;
if(pos <=mid) update(t[pre].ls,t[now].ls,pos,l,mid);
else update(t[pre].rs,t[now].rs,pos,mid+1,r);
push_up(now,r-l+1);
}
node qry(int now,int L,int R,int l,int r){
if(L<=l && r<=R){
return t[now];
}
int mid = l+r>>1, m=r-l+1, rm=m>>1, lm=m-rm;
node ls,rs,ans;
if(L <= mid) ls = qry(t[now].ls,L,R,l,mid);
if(R > mid) rs = qry(t[now].rs,L,R,mid+1,r);
ans.l = ls.l;
if(ls.l == lm) ans.l+=rs.l;
ans.r = rs.r;
if(rs.r == rm) ans.r+=ls.r;
ans.s = max(ls.r+rs.l,max(ls.s,rs.s));
return ans;
}
int check(int l,int r,int h,int rt){
if(qry(T[rt],l,r,1,n).s >= h) return 1;
return 0;
}
int main(){
ios_base::sync_with_stdio(0);
cin.tie(0);
cin >> n;
rep(i,1,n+1) cin >> a[i].fi , a[i].se = i;
sort(a+1,a+n+1,cmp);
rep(i,1,n+1){
update(T[i-1],T[i],a[i].se,1,n);
}
cin>> q;
while(q--){
int x, y ,m;
cin >> x >> y >> m;
int l=1,r=n;
while(l<=r){
int mid = l+r>>1;
if(check(x,y,m,mid)) r=mid-1;
else l=mid+1;
}
r++;
cout << a[r].fi << endl;
}
return 0;
}