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 << "
";
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 }
原文地址:https://www.cnblogs.com/mjtcn/p/10038054.html