POJ-1769(线段树)

题目:http://poj.org/problem?id=1769

看完题目一想贪心不就可以了吗,写了之后WA,看了discuss才发现自己读题都没读清楚Σ( ° △ °|||)︴

题目要求找出subsequence,想着DP就行了,令f[x]表示覆盖[1,x]的区间至少需要的sorter个数,则对于一个sorter [a,b],有f[b] = min(f[b], f[a]+1),想想又不太对,因为还需要f[b-1] = min(f[b-1], f[a] + 1),f[b-2] = min(f[b-2], f[a] + 1),一直到f[a+1] = min(f[a+1], f[a] + 1),这个复杂度就可能达到O(MN)了,肯定不行。

题目实际上可以这么理解,给一些覆盖区间,问覆盖到第N个点至少需要多少个,感觉有点像区间修改点查询,关注区间的覆盖情况,对于一个sorter [a,b],则区间[a,b]的覆盖 = a点覆盖需要 + 1

需要注意的地方:对于sorter [1, x],则区间[1,x]的覆盖 = 1


#include <cstdio>
#include <algorithm>
using namespace std;
#define MAX	50005
#define INF	999999999

int N, M;
int l[MAX << 2], r[MAX << 2], c[MAX << 2];
void build(int i, int L, int R)
{
	l[i] = L;
	r[i] = R;
	c[i] = INF;
	if(L == R) return;

	int M = (L + R) >> 1;
	build(i << 1, L, M);
	build(i << 1 | 1, M + 1, R);
}
void update(int i, int a, int b, int k)
{
	if(a <= l[i] && r[i] <= b){
		c[i] = min(c[i], k);
		return;
	}

	int m = (l[i] + r[i]) >> 1;
	if(m < a) update(i << 1 | 1, a, b, k);
	else if(b <= m) update(i << 1, a, b, k);
	else{
		update(i << 1, a, m, k);
		update(i << 1 | 1, m+1, b, k);
	}
}
int query(int i, int x)
{
	if(l[i] == r[i]) return c[i];

	c[i << 1]     = min(c[i << 1],     c[i]);
	c[i << 1 | 1] = min(c[i << 1 | 1], c[i]);
	return ((l[i] + r[i]) >> 1) >= x ? query(i << 1, x) : query(i << 1 | 1, x);
}

int main()
{
    int i, x, y, e, k;
	while(~scanf("%d%d", &N, &M)){
		build(1, 1, N);
		for(i = 0; i < M; ++i){
			scanf("%d%d", &x, &y);
			if(x == 1) break;
		}
		update(1, x, y, 1);
		for(++i; i < M; ++i){
			scanf("%d%d", &x, &y);
			update(1, x, y, x == 1 ? 1 : query(1, x) + 1);
		}
		printf("%d\n", query(1, N));
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值