AHOI2018训练题集

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 }
B
扫描二维码关注公众号,回复: 5578880 查看本文章

猜你喜欢

转载自www.cnblogs.com/HocRiser/p/10554515.html
今日推荐