ACday2B
长度为n的排列,每次询问包含区间[l,r]的最短连续段,连续段即值域连续的一个区间。(n,Q<=1e5)
做法一:
首先两个连续段若有交,则其交集与并集都为连续段,那么定义[i,i+1]为“小区间”,则[l,r]的答案就是其中所有小区间的并集。
小区间之间会形成“选了u则必须选v”的关系,连有向边后跑SCC就能得到包含每个小区间的最短连续段(由于连续段的交集也是连续段,所以包含任意区间的最短连续段实际上是唯一的)。线段树优化建图,查询也是线段树区间最值询问问题。
做法二:
将两个值相差1的位置连边,则一个区间为连续段当且仅当它内部的边数=r-l。
将询问离线到右端点,从小到大依次枚举每个点i并考虑将它作为右端点。按左端点递减的顺序回答询问,若当前询问的答案右端点就是i则删除此询问。
那么问题就是找到最大的左端点满足r-l=l~r之间的边数,即r=l+(l~r之间边数)。
每次右移右端点时,加入与它有关的边的影响,这部分可以用线段树区间维护,查询时也是线段树前缀查询最值。
1 #include<set> 2 #include<vector> 3 #include<cstdio> 4 #include<algorithm> 5 #define ls (x<<1) 6 #define rs (ls|1) 7 #define lson ls,L,mid 8 #define rson rs,mid+1,R 9 #define rep(i,l,r) for (int i=(l); i<=(r); i++) 10 using namespace std; 11 12 const int N=100010; 13 int n,m,l,r,a[N],p[N],ans1[N],ans2[N],tag[N<<2]; 14 struct P{ int x,y; }sm[N<<2]; 15 vector<P>ve[N]; 16 set<P>S; 17 bool operator <(const P &a,const P &b){ return a.x==b.x ? a.y>b.y : a.x>b.x; } 18 P operator +(const P &a,const P &b){ return a.x==b.x ? (a.y>b.y?a:b) : (a.x>b.x?a:b); } 19 20 void build(int x,int L,int R){ 21 if (L==R){ sm[x]=(P){L,L}; return; } 22 int mid=(L+R)>>1; 23 build(lson); build(rson); sm[x]=sm[ls]+sm[rs]; 24 } 25 26 void push(int x){ 27 if (!tag[x]) return; 28 sm[ls].x+=tag[x]; sm[rs].x+=tag[x]; 29 tag[ls]+=tag[x]; tag[rs]+=tag[x]; tag[x]=0; 30 } 31 32 void mdf(int x,int L,int R,int l,int r){ 33 if (L==l && r==R){ tag[x]++; sm[x].x++; return; } 34 int mid=(L+R)>>1; push(x); 35 if (r<=mid) mdf(lson,l,r); 36 else if (l>mid) mdf(rson,l,r); 37 else mdf(lson,l,mid),mdf(rson,mid+1,r); 38 sm[x]=sm[ls]+sm[rs]; 39 } 40 41 P que(int x,int L,int R,int l,int r){ 42 if (L==l && r==R) return sm[x]; 43 int mid=(L+R)>>1; push(x); 44 if (r<=mid) return que(lson,l,r); 45 else if (l>mid) return que(rson,l,r); 46 else return que(lson,l,mid)+que(rson,mid+1,r); 47 } 48 49 bool jud(P x,int id){ 50 P res=que(1,1,n,1,x.x); 51 if (res.x==id){ ans1[x.y]=res.y; ans2[x.y]=id; return 1; } 52 return 0; 53 } 54 55 int main(){ 56 freopen("b.in","r",stdin); 57 freopen("b.out","w",stdout); 58 scanf("%d",&n); 59 rep(i,1,n) scanf("%d",&a[i]),p[a[i]]=i; 60 build(1,1,n); scanf("%d",&m); 61 rep(i,1,m) scanf("%d%d",&l,&r),ve[r].push_back((P){l,i}); 62 rep(i,1,n){ 63 int ed=ve[i].size()-1; rep(j,0,ed) S.insert(ve[i][j]); 64 if (a[i]>1 && p[a[i]-1]<=i) mdf(1,1,n,1,p[a[i]-1]); 65 if (a[i]<n && p[a[i]+1]<=i) mdf(1,1,n,1,p[a[i]+1]); 66 while (S.size()) if (jud(*S.begin(),i)) S.erase(S.begin()); else break; 67 } 68 rep(i,1,m) printf("%d %d\n",ans1[i],ans2[i]); 69 return 0; 70 }