1178: [Apio2009]CONVENTION会议中心
https://lydsy.com/JudgeOnline/problem.php?id=1178
分析:
set+倍增。
首先把所有有包含的去掉,只保留包含的最小的边(如果两条线段中的一条包含另一条,那么保留被包含的)然后此时就可以直接贪心了。直接从一条边找不想交的下一条边。然后就行了(因为此时没有包含的,左端点递增,右端点递增)。
因为每条边的下一条是唯一的,那么可以倍增维护往后走2^i步,到的点。此时可以快速知道任意一段区间的最多可以有多少条边了。
因为要字典序最小,从编号小的可以是枚举,如果这条边[l,r]可以加进去。tl,tr如下图所示。
那么[l,r]可以加入的条件是,calc(tl+1,tr-1)=calc(tl+1,l-1)+calc(r+1,tr-1)+1,calc(l,r)表示l~r最多可以放几条线段。
代码:
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #include<iostream> 5 #include<cmath> 6 #include<cctype> 7 #include<set> 8 #include<queue> 9 #include<vector> 10 #include<map> 11 using namespace std; 12 typedef long long LL; 13 14 inline int read() { 15 int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1; 16 for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f; 17 } 18 19 const int N = 200005; 20 const int INF = 1e9; 21 const int Log = 20; 22 23 struct Edge{ 24 int l, r; 25 Edge() { } 26 Edge(int a,int b) { l = a, r = b; } 27 bool operator < (const Edge &A) const { 28 return r == A.r ? l > A.l : r < A.r; 29 } 30 }A[N], ori[N]; 31 int disc[N << 1], f[N][Log + 1], X[N], Y[N], m = 1; 32 set<Edge>s; 33 34 int Calc(int l,int r) { 35 int p = lower_bound(X + 1, X + m + 1, l) - X, ans = 1; // ans=1!!! 36 if (Y[p] > r || p > m) return 0; 37 for (int i = Log; i >= 0; --i) 38 if (f[p][i] && Y[f[p][i]] <= r) 39 ans += (1 << i), p = f[p][i]; 40 return ans; 41 } 42 43 int main() { 44 int n = read(); 45 for (int i = 1; i <= n; ++i) { 46 A[i].l = read(), A[i].r = read(); 47 disc[i] = A[i].l, disc[i + n] = A[i].r; 48 } 49 sort(disc + 1, disc + n + n + 1); 50 int cnt = 1; 51 for (int i = 2; i <= n + n; ++i) if (disc[i] != disc[cnt]) disc[++cnt] = disc[i]; 52 for (int i = 1; i <= n; ++i) { 53 A[i].l = lower_bound(disc + 1, disc + cnt + 1, A[i].l) - disc; 54 A[i].r = lower_bound(disc + 1, disc + cnt + 1, A[i].r) - disc; 55 ori[i] = A[i]; 56 } 57 sort(A + 1, A + n + 1); 58 X[m] = A[m].l, Y[m] = A[m].r; 59 for (int i = 2; i <= n; ++i) 60 if (A[i].l > A[m].l) A[++m] = A[i], X[m] = A[m].l, Y[m] = A[m].r; 61 for (int i = 1, j = 1; i <= m; ++i) { 62 while (j <= m && A[j].l <= A[i].r) j ++; 63 if (j <= m) f[i][0] = j; 64 } 65 for (int j = 1; j <= Log; ++j) 66 for (int i = 1; i <= m; ++i) f[i][j] = f[f[i][j - 1]][j - 1]; 67 68 int ans = Calc(-INF, INF); 69 cout << ans << " "; 70 71 s.insert(Edge(INF, INF)); 72 s.insert(Edge(-INF, -INF)); 73 74 int now = 0; 75 for (int i = 1; i <= n; ++i) { 76 set<Edge> :: iterator x = s.lower_bound(ori[i]), y = x; y --; // 端点没有重复的,可以直接set的lower_bound 77 int tl = y->r, tr = x->l, l = ori[i].l, r = ori[i].r; 78 if (tl >= l || tr <= r) continue; 79 if (Calc(tl + 1, tr - 1) == Calc(tl + 1, l - 1) + Calc(r + 1, tr - 1) + 1) { 80 if (++now == ans) return printf("%d",i), 0; 81 else printf("%d ",i); 82 s.insert(ori[i]); 83 } 84 } 85 return 0; 86 }