POJ 1201 树状数组 + 贪心

大致题意

有n个区间[ai, bi],每个区间至少要包含ci个元素,求满足所有区间要求的最小整数集合大小。
1 <= n <= 50000, 0 <= ai <= bi <= 50000, 1 <= ci <= bi - ai+1

树状数组 + 贪心

区间较小,直接用树状数组维护区间元素个数,最终元素个数可以sum(MAX_N)求出。考虑到树状数组索引特性,ai、bi区间向右平移一个单位,变为[1, 50001]。

求最小元素个数,可以贪心法,对区间排序,再将元素放到区间最右侧即可。一开始直接在每个区间的 bi上加ci 与区间元素的正差值,然后就WA了。跑测试数据结果居然比答案还小,Emmmm意识到了什么,题中1 <= ci <= bi - ai+1 的意思是,元素是离散的整数点。很可能在 bi 处加上的值超出了区间元素个数,还是从 bi 向前遍历好了。排序的时候除了按右边界降序,区间越大、元素越多,越向前排可以提高处理区间的效率。

#include <cstdio>
#include <STDLIB.H>
#include <algorithm>
#include <iostream>
#define min(a,b)    (((a) < (b)) ? (a) : (b))
#define max(a,b)    (((a) > (b)) ? (a) : (b))
#define abs(x)    ((x) <0 ? -(x): x)
#define INF 0x3f3f3f3f
#define eps 1e-4
#define M_PI 3.14159265358979323846
#define MAX_N 50001
using namespace std;
struct itv{
	int a, b, c;
	itv(){}
};
bool cmp(const itv& i1, const itv& i2){
	if(i1.b != i2.b) return i1.b < i2.b;
	else if(i1.a != i2.a) return i1.a < i2.a;
	return i1.c > i2.c;
}
int N;
bool used[MAX_N];
itv S[MAX_N];
int bit[MAX_N + 1];
int sum(int i){
	int s = 0;
	while(i > 0){
		s += bit[i];
		i -= i & -i;
	}
	return s;
}
void add(int i){
	while(i <= MAX_N){
		++bit[i];
		i += i & -i;
	}
}
void solve(){
	for(int i = 0; i < N; i++){
		int dif = S[i].c - sum(S[i].b) + sum(S[i].a), idx = S[i].b;
		while(dif > 0){
			while(used[idx]) --idx;
			used[idx] = true, --dif;
			add(idx);
		}
	}
	printf("%d\n", sum(MAX_N));
}
int main(){
	scanf("%d", &N);
	memset(bit, 0, sizeof(bit));
	for(int i = 0; i < N; i++){
		scanf("%d%d%d", &S[i].a, &S[i].b, &S[i].c);
		++S[i].b;  //(a, b]
	}
	sort(S, S + N, cmp);
	memset(used, false, sizeof(used));
	solve();
	return 0;
}
发布了6 篇原创文章 · 获赞 0 · 访问量 49

猜你喜欢

转载自blog.csdn.net/neweryyy/article/details/104323930
今日推荐