CERC 2017 gym 101620 Problem I: Intrinsic Interval

重要性质:若区间\([l_1,r_1]\)合法,区间\([l_2,r_2]\)也合法,其中满足\(l_1<l_2<r_1<r_2\)

可以轻轻松松证明:\([l_2,r_1]\)也合法!

也就是说若我们规定两个数L,R,其中对于所有>=R的位置i,求出在最大的\(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;
}
/** 程序框架:
  *
  *
  *
  *
  **/


(不过这题貌似可以分治在线的,欢迎评论)

posted @ 2020-11-20 23:55  WWW~~~  阅读(91)  评论(0编辑  收藏  举报