[CERC2017]Intrinsic Interval(神仙+线段树)
Posted zh-comld
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[CERC2017]Intrinsic Interval(神仙+线段树)相关的知识,希望对你有一定的参考价值。
题目大意:给一个1-n的排列,有一堆询问区间,定义一个好的区间为它的值域区间长度等于它的区间长度,求包这个询问区间的最小好的区间。
题解
做法太神了,根本想不到。
%%%i207m。
结论:当一个区间中相邻的数的对数等于区间长度-1,那么这个区间是好的区间,证明:*%%%%……*%%¥。
所以我们可以用扫描线对1-n扫一遍,用线段树维护i-now的相邻的数的对数,如果我们令a[i]+=i;那么当我们做到r时且a[l]=r,那么l到r是好区间。
然后我们对于每个询问按照l从大到小做,如果找不到就break掉。
代码
#include<iostream> #include<cstdio> #include<vector> #include<queue> #define N 100002 using namespace std; int tr[N<<2],la[N<<2],mx[N<<2],nowma,ga,zuo,n,pos[N],m,ansl[N],ansr[N],a[N]; inline int rd(){ int x=0;char c=getchar();bool f=0; while(!isdigit(c)){if(c==‘-‘)f=1;c=getchar();} while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();} return f?-x:x; } struct Q{ int l,r,id; bool operator <(const Q &b)const{return l<b.l;} }; vector<Q>vec[N]; priority_queue<Q>q; inline void pushdown(int cnt){ tr[cnt<<1]+=la[cnt];tr[cnt<<1|1]+=la[cnt]; la[cnt<<1]+=la[cnt];la[cnt<<1|1]+=la[cnt]; la[cnt]=0; } inline void pushup(int cnt){ tr[cnt]=tr[cnt<<1];mx[cnt]=mx[cnt<<1]; if(tr[cnt<<1|1]==tr[cnt])mx[cnt]=max(mx[cnt],mx[cnt<<1|1]); else if(tr[cnt<<1|1]>tr[cnt])tr[cnt]=tr[cnt<<1|1],mx[cnt]=mx[cnt<<1|1]; } void build(int cnt,int l,int r){ if(l==r){tr[cnt]=l;mx[cnt]=l;return;} int mid=(l+r)>>1; build(cnt<<1,l,mid);build(cnt<<1|1,mid+1,r); pushup(cnt); } void upd(int cnt,int l,int r,int L,int R){ if(l>=L&&r<=R){tr[cnt]++;la[cnt]++;return;} int mid=(l+r)>>1; if(la[cnt])pushdown(cnt); if(mid>=L)upd(cnt<<1,l,mid,L,R); if(mid<R)upd(cnt<<1|1,mid+1,r,L,R); pushup(cnt); } void query(int cnt,int l,int r,int L,int R){ if(l>=L&&r<=R){ if(tr[cnt]>=nowma){nowma=tr[cnt];zuo=mx[cnt];} return; } int mid=(l+r)>>1; if(la[cnt])pushdown(cnt); if(mid>=L)query(cnt<<1,l,mid,L,R); if(mid<R)query(cnt<<1|1,mid+1,r,L,R); } inline bool pd(Q a){ int l=a.l,r=a.r,id=a.id;nowma=0; query(1,1,n,1,l); // cout<<nowma<<" __ "<<ga<<endl; if(nowma==ga){ ansl[id]=zuo;ansr[id]=ga;return 1; } return 0; } int main(){ n=rd(); build(1,1,n); for(int i=1;i<=n;++i)a[i]=rd(),pos[a[i]]=i; m=rd(); for(int i=1;i<=m;++i){ int l=rd();int r=rd(); vec[r].push_back(Q{l,r,i}); } for(int i=1;i<=n;++i){ ga=i; if(a[i]>1&&pos[a[i]-1]<=i)upd(1,1,n,1,pos[a[i]-1]); if(a[i]<n&&pos[a[i]+1]<=i)upd(1,1,n,1,pos[a[i]+1]); for(int j=0;j<vec[i].size();++j)q.push(vec[i][j]); while(!q.empty()){if(pd(q.top()))q.pop();else break;} } for(int i=1;i<=m;++i)printf("%d %d ",ansl[i],ansr[i]); return 0; }
以上是关于[CERC2017]Intrinsic Interval(神仙+线段树)的主要内容,如果未能解决你的问题,请参考以下文章
[CERC2017]Intrinsic Interval(神仙+线段树)
[CERC2017]Intrinsic Interval[scc+线段树优化建图]
做题CERC2017B. Buffalo Barricades——时间倒流