bzoj 1178 [Apio2009]CONVENTION会议中心

时间:2023-03-10 08:40:30
bzoj 1178  [Apio2009]CONVENTION会议中心

这题好难啊! 我好菜啊!

思路:对于最多线段不相交, 我们可以按左端点sort之后,贪心取。 但是这个题要求选取的线段排序之后序号的字典序最小。

那么我们如果按序号贪心地从大往小往里放, 那么对于第k个线段,我们考虑放进去之后是能是还能保证所取的线段个数能

达到最大, 我们考虑函数cal(l, r) 表示坐标轴上l 到 r 最多能选取多少线段,第k条线段的左右端点是l, r, 它左边第一条是l1, r1

它右边第一条是l2, r2, 那么k能放进去的充分必要条件就是cal(r1 + 1, l2 - 1) == cal(r1 + 1, l - 1) + cal(r + 1, l2 - 1) + 1。

那么我们的问题就变成了cal()这个函数如何实现,我们将原来的线段按右端点排序之后,把包含其他线段的线段全部删掉,

然后nx[ i ][ 0 ] = k 表示 k是第一个满足b[k].l > b[i].r 的线段, 然后我们再倍增一下,求出nx[ i ][ j ]表示 i 右边第2^j 个线段是谁。

 #include<bits/stdc++.h>
#define LL long long
#define fi first
#define se second
#define mk make_pair
#define pii pair<int,int>
#define piii pair<int, pair<int,int>> using namespace std; const int N=+;
const int M=1e4+;
const int inf=0x3f3f3f3f;
const LL INF=0x3f3f3f3f3f3f3f3f;
const int mod=1e9 + ; int n, m, nx[N][], L[N], R[N]; struct Line {
int l, r; Line(int _l = , int _r = ) {
l = _l;
r = _r;
}
bool operator < (const Line &rhs) const {
if(r == rhs.r) return l < rhs.l;
return r < rhs.r;
} } a[N], b[N]; int cal(int l, int r) {
int x = lower_bound(L + , L + + m, l) - L;
if(x > m || R[x] > r) return ;
int ans = ;
for(int i = ; i >= ; i--) {
if(nx[x][i] && R[nx[x][i]] <= r) {
ans += << i;
x = nx[x][i];
}
}
return ans;
}
int main() { scanf("%d", &n);
for(int i = ; i <= n; i++) {
scanf("%d%d", &a[i].l, &a[i].r);
b[i] = a[i];
} sort(b + , b + n + ); for(int i = ; i <= n; i++) {
if(!m || b[i].l > b[m].l)
b[++m] = b[i];
} for(int i = ; i <= m; i++)
L[i] = b[i].l, R[i] = b[i].r; for(int i = , j = ; i <= m; i++) {
while(j <= m && b[j].l <= b[i].r) j++;
if(j <= m) nx[i][] = j;
} for(int i = ; i <= ; i++) {
for(int j = ; j <= m; j++) {
nx[j][i] = nx[nx[j][i - ]][i - ];
}
} int ans = cal(-inf, inf);
printf("%d\n", ans);
set<Line> st;
int cnt = ;
st.insert(Line(inf, inf));
st.insert(Line(-inf, -inf)); for(int i = ; i <= n; i++) {
set<Line>::iterator it = st.lower_bound(a[i]), itt = it; itt--;
int l1 = itt -> r, r1 = a[i].l, l2 = a[i].r, r2 = it -> l;
if(l1 >= r1 || l2 >= r2) continue;
if(cal(l1 + , r2 - ) == cal(l1 + , r1 - ) + cal(l2 + , r2 - ) + ) {
if(++cnt == ans) printf("%d", i);
else printf("%d ", i);
st.insert(a[i]);
}
}
puts("");
return ;
}
/*
*/