[BZOJ2811][Apio2012]Guard
试题描述
输入
输出
输入示例
5 3 4 1 2 1 3 4 1 4 4 0 4 5 1
输出示例
3 5
数据规模及约定
见“试题描述”
题解
首先 Ci = 0 的区间必定都为 0,打个离线标记啥的把该标 0 的标成 0,看剩下的 1 的个数是否为 K,如果是那么所有的位置都是必填的。
考虑剩下的情况,我们给 1 的位置重新标号,区间也对应重新标号一下,把包含了其他区间的区间删除,然后正反贪心一波。令 f[i] 表示前 i 个区间至少需要多少个点,g[i] 表示后 N-i+1 个区间至少需要几个点(N 表示区间个数);依次检查每个区间的右端点(设它为 x)是否能够被 x-1 取代,方法是二分找到 x-1 能够管道的区间都有哪些,设这些区间的编号为 [l, r],那么 f[l-1] + 1 + g[r+1] > K 的时候 x 就不能被取代。
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <cctype> #include <algorithm> using namespace std; int read() { int x = 0, f = 1; char c = getchar(); while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); } while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); } return x * f; } #define maxn 100010 #define maxlog 17 int n, m, K, tag[maxn], A[maxn], S[maxn], id[maxn], lst[maxn], lstr[maxn], cntl; struct Line { int l, r; Line() {} Line(int _, int __): l(_), r(__) {} bool operator < (const Line& t) const { return r != t.r ? r < t.r : l > t.l; } } ls[maxn]; bool has[maxn]; int f[maxn], g[maxn], pos[maxn]; int main() { n = read(); K = read(); m = read(); for(int i = 1; i <= m; i++) { int l = read(), r = read(), tp = read(); if(tp) ls[++cntl] = Line(l, r); else tag[l]++, tag[r+1]--; } int now = 0, lst1 = 0, cnt = 0; for(int i = 1; i <= n; i++) { now += tag[i]; if(now) A[i] = 0; else A[i] = 1; cnt += A[i]; if(A[i]) id[i] = id[lst1] + 1, pos[id[i]] = i; if(A[i]) lst1 = i; lst[i] = lst1; } // for(int i = 1; i <= n; i++) printf("%d%c", id[i], i < n ? ' ' : ' '); lst1 = n + 1; for(int i = n; i; i--) { if(A[i]) lst1 = i; lstr[i] = lst1; } if(!cnt) return puts("-1"), 0; if(cnt == K) { for(int i = 1; i <= n; i++) if(A[i]) printf("%d ", i); return 0; } for(int i = 1; i <= cntl; i++) ls[i].l = id[lstr[ls[i].l]], ls[i].r = id[lst[ls[i].r]]; sort(ls + 1, ls + cntl + 1); int tc = cntl; cntl = 0; for(int i = 1; i <= tc;) { int j = i + 1; ls[++cntl] = ls[i]; while(ls[j].l <= ls[i].l && ls[i].r <= ls[j].r) j++; i = j; } // for(int i = 1; i <= cntl; i++) printf("[%d, %d] ", ls[i].l, ls[i].r); for(int i = 1; i <= cntl;) { int j = i + 1; has[i] = 1; f[i] = f[i-1] + 1; while(j <= cntl && ls[j].l <= ls[i].r && ls[i].r <= ls[j].r) f[j++] = f[i]; i = j; } for(int i = cntl; i;) { int j = i - 1; g[i] = g[i+1] + 1; while(j && ls[j].l <= ls[i].l && ls[i].l <= ls[j].r) g[j--] = g[i]; i = j; } // puts("here"); bool ok = 0; for(int i = 1; i <= cntl; i++) if(has[i]) { if(ls[i].l == ls[i].r) { printf("%d ", pos[ls[i].l]); ok = 1; continue; } int x = ls[i].r - 1, l = 1, r = i, L, R; while(l < r) { int mid = l + r >> 1; if(ls[mid].r < x) l = mid + 1; else r = mid; } L = l; l = i; r = cntl + 1; while(r - l > 1) { int mid = l + r >> 1; if(ls[mid].l > x) r = mid; else l = mid; } R = l; if(f[L-1] + 1 + g[R+1] > K) printf("%d ", pos[ls[i].r]), ok = 1; } if(!ok) puts("-1"); return 0; }