[BZOJ2811][Apio2012]Guard

[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 ? ' ' : '\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;
}

 

posted @ 2017-03-30 11:34  xjr01  阅读(182)  评论(0编辑  收藏  举报