1. 程式人生 > >1178: [Apio2009]CONVENTION會議中心

1178: [Apio2009]CONVENTION會議中心

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 << "\n"; 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 }