重要性质:若区间 [ l 1 , r 1 ] [l_1,r_1] [l1,r1]合法,区间 [ l 2 , r 2 ] [l_2,r_2] [l2,r2]也合法,其中满足 l 1 < l 2 < r 1 < r 2 l_1<l_2<r_1<r_2 l1<l2<r1<r2。
可以轻轻松松证明: [ l 2 , r 1 ] [l_2,r_1] [l2,r1]也合法!
也就是说若我们规定两个数L,R,其中对于所有>=R的位置i,求出在最大的 x x x满足x<=L且,[x,i]合法。对于每一个i记录这个位置为x[i]。
可以发现什么?
x[i]递减!(如果x[i]有的话)
根据上面的那个东西就可以证明。
则对于询问l[i],r[i]。我们只需要找到最近的那一个i(i>=r[i])满足最小的合法左端点<=l[i],在则这个询问的答案的右端点已经可以确认是i。
那么如何确定某一个位置的最小左端点呢?
若一个区间l,r合法,则满足max(Π[l]…Π[r])-min(Π[l]…Π[r])-r+l=0,可以发现这个式子的最小值就是0。
则我们可以从前往后扫过去,维护一个支持区间+和区间取min的线段树就ok了。min/max 这些就交给单调栈。
这样x[i]就可以算出来了。
我们将上面的询问离线下来,就可以对于每一个右端点枚举以它为右端点的询问。然后线段树上二分就行了。
Code:
/*
{
######################
# Author #
# Gary #
# 2020 #
######################
*/
//#pragma GCC target ("avx2")
//#pragma GCC optimization ("O3")
//#pragma GCC optimization ("unroll-loops")
#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define rb(a,b,c) for(int a=b;a<=c;++a)
#define rl(a,b,c) for(int a=b;a>=c;--a)
#define LL long long
#define IT iterator
#define PB push_back
#define II(a,b) make_pair(a,b)
#define FIR first
#define SEC second
#define FREO freopen("check.out","w",stdout)
#define rep(a,b) for(int a=0;a<b;++a)
#define SRAND mt19937 rng(chrono::steady_clock::now().time_since_epoch().count())
#define random(a) rng()%a
#define ALL(a) a.begin(),a.end()
#define POB pop_back
#define ff fflush(stdout)
#define fastio ios::sync_with_stdio(false)
#define check_min(a,b) a=min(a,b)
#define check_max(a,b) a=max(a,b)
using namespace std;
//inline int read(){
// int x=0;
// char ch=getchar();
// while(ch<'0'||ch>'9'){
// ch=getchar();
// }
// while(ch>='0'&&ch<='9'){
// x=(x<<1)+(x<<3)+(ch^48);
// ch=getchar();
// }
// return x;
//}
const int INF=0x3f3f3f3f;
typedef pair<int,int> mp;
/*}
*/
const int N=1<<17;
struct SEGMENT_TREE_SMALL_POSITION{
mp tree[N+N];//最小值,最小位置
int tag[N+N];
SEGMENT_TREE_SMALL_POSITION(){
memset(tag,0,sizeof(tag));
rb(i,1,N)
tree[i+N-1]=II(0,i);
rl(i,N-1,1)
tree[i]=min(tree[i<<1],tree[i<<1|1]);
}
void pd(int now){
tree[now].FIR+=tag[now];
if(now<N) tag[now<<1]+=tag[now],tag[now<<1|1]+=tag[now];
tag[now]=0;
}
void pu(int now){
tree[now]=min(tree[now<<1],tree[now<<1|1]);
}
void modify(int a,int b,int val,int now=1,int l=1,int r=N+1){
pd(now);
if(r<=b&&l>=a){
tag[now]+=val;
pd(now);
return ;
}
if(r<=a||l>=b){
return ;
}
int mid=(l+r)>>1;
modify(a,b,val,now<<1,l,mid);
modify(a,b,val,now<<1|1,mid,r);
pu(now);
}
mp query(int a,int b,int now=1,int l=1,int r=N+1){
pd(now);
if(r<=a||l>=b) return II(INF,INF);
if(r<=b&&l>=a) return tree[now];
int mid=(l+r)>>1;
return min(query(a,b,now<<1,l,mid),query(a,b,now<<1|1,mid,r));
}
}ts;
struct SEGMENT_TREE_BIG_POSITION{
mp tree[N+N];//最小值,最小位置
int tag[N+N];
SEGMENT_TREE_BIG_POSITION(){
memset(tag,0,sizeof(tag));
rb(i,1,N)
tree[i+N-1]=II(0,-i);
rl(i,N-1,1)
tree[i]=min(tree[i<<1],tree[i<<1|1]);
}
void pd(int now){
tree[now].FIR+=tag[now];
if(now<N) tag[now<<1]+=tag[now],tag[now<<1|1]+=tag[now];
tag[now]=0;
}
void pu(int now){
tree[now]=min(tree[now<<1],tree[now<<1|1]);
}
void modify(int a,int b,int val,int now=1,int l=1,int r=N+1){
pd(now);
if(r<=b&&l>=a){
tag[now]+=val;
pd(now);
return ;
}
if(r<=a||l>=b){
return ;
}
int mid=(l+r)>>1;
modify(a,b,val,now<<1,l,mid);
modify(a,b,val,now<<1|1,mid,r);
pu(now);
}
mp query(int a,int b,int now=1,int l=1,int r=N+1){
pd(now);
if(r<=a||l>=b) return II(INF,INF);
if(r<=b&&l>=a) return tree[now];
int mid=(l+r)>>1;
return min(query(a,b,now<<1,l,mid),query(a,b,now<<1|1,mid,r));
}
}tb;
int n;
stack<pair<mp,int> > ss,bs;//min and max
int a[100000+20],x[100000+20];
deque<mp> zz;//val pos
vector<int> ls[100000+20];
vector<int> lq[100000+20];
mp ret[100000+20];
int l[100000+20];
int main(){
scanf("%d",&n);
rb(i,1,n) scanf("%d",&a[i]);
rb(i,1,n){
mp seg=II(i,i);
while(!ss.empty()&&ss.top().SEC>=a[i]){
mp segg=ss.top().FIR;
int val=ss.top().SEC;
ts.modify(segg.FIR,segg.SEC+1,val);
seg.FIR=segg.FIR;
ss.pop();
}
// cout<<seg.FIR<<' '<<seg.SEC<<' ';
ts.modify(seg.FIR,seg.SEC+1,-a[i]);
ss.push(II(seg,a[i]));
seg=II(i,i);
while(!bs.empty()&&bs.top().SEC<=a[i]){
mp segg=bs.top().FIR;
int val=bs.top().SEC;
ts.modify(segg.FIR,segg.SEC+1,-val);
seg.FIR=segg.FIR;
bs.pop();
}
// cout<<seg.FIR<<' '<<seg.SEC<<' ';
ts.modify(i,i+1,i);
ts.modify(seg.FIR,seg.SEC+1,a[i]);
bs.push(II(seg,a[i]));
mp rett=ts.query(1,i+1);
assert(rett.FIR==i);
x[i]=rett.SEC;
}
int q;
scanf("%d",&q);
rb(i,1,q){
int li,ri;
scanf("%d%d",&li,&ri);
l[i]=li;
ls[ri].PB(i);
}
rl(i,n,1){
while(!zz.empty()&&zz.front().FIR>=x[i]){
zz.pop_front();
}
zz.push_front(II(x[i],i));
for(auto it:ls[i]){
int lbound=0,rbound=zz.size()-1;
while(lbound<rbound){
int mid=(lbound+rbound)>>1;
if(zz[mid].FIR>l[it]){
lbound=mid+1;
}
else{
rbound=mid;
}
}
lq[zz[lbound].SEC].PB(it);
}
}
while(!ss.empty()) ss.pop();
while(!bs.empty()) bs.pop();
rb(i,1,n){
mp seg=II(i,i);
while(!ss.empty()&&ss.top().SEC>=a[i]){
mp segg=ss.top().FIR;
int val=ss.top().SEC;
tb.modify(segg.FIR,segg.SEC+1,val);
seg.FIR=segg.FIR;
ss.pop();
}
tb.modify(seg.FIR,seg.SEC+1,-a[i]);
ss.push(II(seg,a[i]));
seg=II(i,i);
while(!bs.empty()&&bs.top().SEC<=a[i]){
mp segg=bs.top().FIR;
int val=bs.top().SEC;
tb.modify(segg.FIR,segg.SEC+1,-val);
seg.FIR=segg.FIR;
bs.pop();
}
tb.modify(i,i+1,i);
tb.modify(seg.FIR,seg.SEC+1,a[i]);
bs.push(II(seg,a[i]));
for(auto it:lq[i]){
mp rett=tb.query(1,l[it]+1);
assert(rett.FIR==i);
ret[it]=II(-rett.SEC,i);
}
}
rb(i,1,q){
printf("%d %d\n",ret[i].FIR,ret[i].SEC);
}
return 0;
}
/** 程序框架:
*
*
*
*
**/
(不过这题貌似可以分治在线的,欢迎评论)