P4747 [CERC2017]Intrinsic Interval
P4747 [CERC2017]Intrinsic Interval
前言
这道题有高大上的析合树做法
不过我不会,可能退役后会考虑学学吧。
这题还有线段树优化建边缩点的好办法。
我还是不会,可能以后会学学吧。
题目大意
其实题目里面讲的很清楚了。
简单的说就是给你一个\(1\) ~\(n\)的排列
定义如果一个区间\([l,r]\)是好区间,仅当\(l\)至\(r\)的序列中的数排序后是连续的。
其实就是有\(r-l\)个相邻的数。
对于每个询问\([L,R]\)让你找出最小的包含\([L,R]\)的好区间。
思想分析
我们发现好区间显然是可以合并的。
如果\([l_1,r_1]\),\([l_2,r_2](l_1<l_2<r_1<r_2)\)都是好区间,那么区间\([l_1,r_2]\)肯定是好区间。
于是我们离线询问后使用扫描线
当我们扫描到\(r\)时,我们就可以处理右端点为\(r\)的所有询问。
也就是说我们要维护最大的左端点\(l\)。
考虑利用好区间的性质,一个区间\([l,r]\)是好区间仅当区间中有\(r-l\)个相邻的数
不难想到令线段树的\(val[i]=i\),设\(sa[i]\)为值\(a[i]\)出现的位置
我们扫描到一个数\(a[i]\)时将区间\([1,sa[a[i]-1]],[1,sa[a[i]+1]]\)都区间加上\(1\)。
那么如果有\(val[l]=r\),\([l,r]\)一定是好区间。
那么我们对于一个节点维护一个最大\(r\)值,与\(r\)出现的位置就可以了。
如果对于一个询问\(ql\),如果线段树中查询\(ql\)的最大\(r\)值等于\(qr\),我们就成功的回答了这个询问。
代码实现
/*
@Date : 2019-09-02 20:24:12
@Author : Adscn (adscn@qq.com)
@Link : https://www.cnblogs.com/LLCSBlog
*/
#include<bits/stdc++.h>
using namespace std;
#define IL inline
#define RG register
#define gi getint()
#define gc getchar()
#define File(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout)
template<typename T>IL bool chkmax(T &x,const T &y){return x<y?x=y,1:0;}
template<typename T>IL bool chkmin(T &x,const T &y){return x>y?x=y,1:0;}
IL int getint()
{
RG int xi=0;
RG char ch=gc;
bool f=0;
while(!isdigit(ch))ch=='-'?f=1:f,ch=gc;
while(isdigit(ch))xi=xi*10+ch-48,ch=gc;
return f?-xi:xi;
}
template<typename T>
IL void pi(T k,char ch=0)
{
if(k<0)k=-k,putchar('-');
if(k>=10)pi(k/10,0);
putchar(k%10+'0');
if(ch)putchar(ch);
}
const int N=1e5+7;
int a[N],b[N];
int mx[N*4],pos[N*4],lz[N*4];
#define ls (rt<<1)
#define rs (rt<<1|1)
#define mid ((l+r)>>1)
int M,P;
IL void pushup(int rt){
if(mx[ls]>mx[rs])mx[rt]=mx[ls],pos[rt]=pos[ls];
else mx[rt]=mx[rs],pos[rt]=pos[rs];
}
IL void pusht(int rt,int val){mx[rt]+=val,lz[rt]+=val;}
IL void pushdown(int rt){if(lz[rt])pusht(ls,lz[rt]),pusht(rs,lz[rt]),lz[rt]=0;}
IL void build(int rt,int l,int r){
mx[rt]=pos[rt]=r;
if(l==r)return;
build(ls,l,mid),build(rs,mid+1,r);
}
IL void modify(int rt,int l,int r,int L,int R,int val){
if(L<=l&&r<=R){pusht(rt,val);return;}
pushdown(rt);
if(L<=mid)modify(ls,l,mid,L,R,val);
if(R>mid)modify(rs,mid+1,r,L,R,val);
pushup(rt);
}
IL void query(int rt,int l,int r,int L,int R)
{
if(L<=l&&r<=R){if(mx[rt]>M)M=mx[rt],P=pos[rt];return;}
pushdown(rt);
if(R>mid)query(rs,mid+1,r,L,R);
if(L<=mid)query(ls,l,mid,L,R);
}
int n;
typedef pair<int,int> pii;
#define fi first
#define se second
vector<pii> G[N];
priority_queue<pii> s;
pii ans[N];
bool judge(pii x,int r){
M=P=0;
query(1,1,n,1,x.fi);
if(M==r){ans[x.se]=make_pair(P,M);return 1;}
return 0;
}
int main(void)
{
n=gi;
for(int i=1;i<=n;++i)a[i]=gi,b[a[i]]=i;
int m=gi;
for(int i=1;i<=m;++i){int l=gi,r=gi;G[r].push_back(make_pair(l,i));}
build(1,1,n);
for(int i=1;i<=n;++i)
{
if(a[i]>1&&b[a[i]-1]<=i)modify(1,1,n,1,b[a[i]-1],1);
if(a[i]<n&&b[a[i]+1]<=i)modify(1,1,n,1,b[a[i]+1],1);
for(int j=0;j<G[i].size();++j)s.push(G[i][j]);
while(!s.empty()){
if(judge(s.top(),i))s.pop();
else break;
}
}
for(int i=1;i<=m;++i)pi(ans[i].fi,' '),pi(ans[i].se,'\n');
return 0;
}