[BZOJ2811][Apio2012]Guard
[BZOJ2811][Apio2012]Guard
试题描述
.jpg)
输入
.jpg)
输出

输入示例
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 ? ' ' : '\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\n", 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]\n", 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\n", 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\n", pos[ls[i].r]), ok = 1;
}
if(!ok) puts("-1");
return 0;
}

浙公网安备 33010602011771号