思路
这一题的正解是倍增的,但是由于我太蒟蒻了,所以我选了一个不算正解但是有可以拿满分的题目学习
思路和我考场上其实差不多,只是我无法实现....
下面我先来介绍几个数组的用途
1.s,s数组代表的是枚举的i时,包括i区间在内最多有多少个区间
2.p数组,p[i]记录的是在这一区间和这一区间之前,字典序最小的并且满足使区间数最多的区间的位置
3.而pr数组代表的是由哪一个区间+1转移过来的...(大概是这个意思,表达能力不是很好)
然后我们就要讨论情况了
第一种情况是我们对这个区间有更新,就是说是由这个区间加上它前面的区间可以构成一个更大的区间总和
第二种情况就是守老本,看上一层得到的解是否依然更加优秀
所以我们就要有不同的处理方式
m是在该区间之前,满足其r最接近当前区间的l的,然后我们就看
如果:
s[m]+1>s[i-1] ,我们就要更新,即p[i]=i,s[i]=s[m]+1;
s[m]+1<s[i-1],我们就守老本,即p[i]=p[i-1],s[i]=s[i-1];
但是还有一种情况,就是2者相等,这是我们就要有选择了,因为我们既然选择了这个,后面的方案就是确定了的,但是前面的方案我们就要选择更优的,即字典序更小的
那就是判断了,具体见代码
tips:是由那个点转移过来的我们要记录好,到时候判断更优的时候需要
二分就不要问我了,我也有点小蒙
1 #include<bits/stdc++.h> 2 #define ll long long 3 #define FOR(i,a,b) for(register int i=a;i<=b;i++) 4 #define ROF(i,a,b) for(register int i=a;i>=b;i--) 5 using namespace std; 6 const int N=200000+10; 7 int n; 8 int p[N],pr[N],s[N]; 9 int q[N]; 10 struct s1 11 { 12 int l,r,id; 13 }a[N]; 14 bool cmp(s1 x,s1 y) 15 { 16 return x.r<y.r; 17 } 18 int scan() 19 { 20 int as=0,f=1; 21 char c=getchar(); 22 while(c>'9'||c<'0'){if(c=='-') f=-1;c=getchar();} 23 while(c>='0'&&c<='9'){as=(as<<3)+(as<<1)+c-'0';c=getchar();} 24 return as*f; 25 } 26 int main() 27 { 28 n=scan(); 29 FOR(i,1,n) 30 { 31 a[i].l=scan();a[i].r=scan();a[i].id=i; 32 } 33 sort(a+1,a+n+1,cmp); 34 FOR(i,1,n) 35 { 36 int l=0,r=i-1,m=0; 37 while(l<=r) 38 { 39 int mid=(l+r)>>1; 40 if(a[mid].r<a[i].l) m=mid,l=mid+1; 41 else r=mid-1; 42 } 43 //现在我们找到了最近的一个区间 44 int f=s[m]+1; 45 pr[i]=p[m]; 46 if(f>s[i-1]) s[i]=f,p[i]=i; 47 else if(s[i-1]>f) s[i]=s[i-1],p[i]=p[i-1]; 48 else 49 { 50 int p1=p[i-1],p2=i,min1=1e9,min2=1e9; 51 while(pr[p1]!=pr[p2]) 52 { 53 if(a[p1].id<min1) min1=a[p1].id; 54 if(a[p2].id<min2) min2=a[p2].id; 55 p1=pr[p1];p2=pr[p2]; 56 } 57 if(a[p1].id<min1)min1=a[p1].id;//处理"祖先"相同但当前结点不同 58 if(a[p2].id<min2) min2=a[p2].id; 59 if(min1<min2) s[i]=s[i-1],p[i]=p[i-1]; 60 else s[i]=f,p[i]=i,pr[i]=p[m]; 61 } 62 } 63 int now=p[n],top=0; 64 cout<<s[n]<<endl; 65 while(now) 66 { 67 q[++top]=a[now].id;now=pr[now]; 68 } 69 sort(q+1,q+top+1); 70 FOR(i,1,top) cout<<q[i]<<" "; 71 return 0; 72 }