P4747 [CERC2017]Intrinsic Interval
Posted llcsblog
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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;
以上是关于P4747 [CERC2017]Intrinsic Interval的主要内容,如果未能解决你的问题,请参考以下文章
[CERC2017]Intrinsic Interval(神仙+线段树)
[CERC2017]Intrinsic Interval[scc+线段树优化建图]