首页 > 其他 > 详细

洛谷P1937 [USACO10MAR]Barn Allocation G

时间:2020-05-30 22:48:52      阅读:40      评论:0      收藏:0      [点我收藏+]

题意:
洛谷P1937 [USACO10MAR]Barn Allocation G

题意:

\(N\)个编号为\(1-N\)的点,每个点有一个权值\(a[i]\)。给你\(M\)个指令,每个指令包含两个数\(l,r\)表示把区间\([l,r]\)的每个点的权值减一。要求每个点的权值不能为负数,求最多能满足几个指令。

题解:

这道题是一道很经典的题"活动安排"的变式,做法和它也很像。

先考虑把所有的指令以右端点为第一关键字从小到大排序,右端点相同则按左端点从小到大排序。遍历排序后的指令,若能满足(即区间\([l,r]\)的最小值大于零)就满足他,否则就跳过。

区间修改和区间最值,用线段树就可以了。

正确性证明:

如果线段不矛盾都选上就好了,所以考虑矛盾的线段,如图:

技术分享图片

考虑线段\([l1,r1]\)\([l2,r2]\)矛盾,也就是\(min([l2,r2])=1\)

此时,如果我们选择区间\([l2,r2]\),并且假设这种方法比\([l1,r1]\)更优,那么多出来的线段一定在区间\([l1,l2]\)中。由于我们是按照区间右端点排序的,所以在\([l1,l2]\)中一定没有别的线段。反观区间\([r1,r2]\)由于选择了第二个区间,所以\([r1,r2]\)与之前相比是多减了1的,一定不比选择\([l1,r1]\)优。

再考虑当两个区间右端点相同,即\([l1,r1],[l2,r1]\),那么此时不论怎么选,都不会对下一条线段产生影响。

代码:

#include<bits/stdc++.h>
using namespace std;
const int N = 100005;
int n, m, a[N], ans;
int T[N << 2], minn[N << 2], lazy[N << 2];
struct node
{
	int l, r;
}nod[N];
bool cmp(node a, node b)
{
	if(a.r != b.r) return a.r < b.r;
	else return a.l < b.l;
}
void pushup(int cnt)
{
	minn[cnt] = min(minn[cnt << 1], minn[cnt << 1 | 1]);
}
void build(int cnt, int l, int r)
{
	if(l == r)
	{
		minn[cnt] = a[l];
		return;
	}
	int mid = l + r >> 1;
	build(cnt << 1, l, mid);
	build(cnt << 1 | 1, mid + 1, r);
	pushup(cnt);
}
void pushdown(int cnt, int l, int r)
{
	if(lazy[cnt])
	{
		minn[cnt << 1] += lazy[cnt];
		minn[cnt << 1 | 1] += lazy[cnt];
		lazy[cnt << 1] += lazy[cnt];
		lazy[cnt << 1 | 1] += lazy[cnt];

		lazy[cnt] = 0;
	}
}
void update(int cnt, int l, int r, int nl, int nr)
{
	if(l >= nl && r <= nr)
	{
		lazy[cnt] -= 1;
		minn[cnt] -= 1;
		return;
	}
	int mid = l + r >> 1;
	pushdown(cnt, l, r);
	if(mid >= nl) update(cnt << 1, l, mid, nl, nr);
	if(mid < nr) update(cnt << 1 | 1, mid + 1, r, nl, nr);
	pushup(cnt);
}
int qmin(int cnt, int l, int r, int nl, int nr)
{
	if(l >= nl && r <= nr) return minn[cnt];
	int mid = l + r >> 1;
	pushdown(cnt, l, r);
	int ans = 999999999;
	if(mid >= nl) ans = min(ans, qmin(cnt << 1, l, mid, nl, nr));
	if(mid < nr) ans = min(ans, qmin(cnt << 1 | 1, mid + 1, r, nl, nr));
	return ans;
}
int main()
{
	scanf("%d%d", &n, &m);
	for(int i = 1; i <= n; i ++) scanf("%d", &a[i]);
	build(1, 1, n);
	for(int i = 1; i <= m; i ++) scanf("%d%d", &nod[i].l, &nod[i].r);
	sort(nod + 1, nod + 1 + m, cmp);
	for(int i = 1; i <= m; i ++)
	{
		if(qmin(1, 1, n, nod[i].l, nod[i].r) > 0)
		{
			update(1, 1, n, nod[i].l, nod[i].r);
			ans ++;
		}
	}
	cout << ans;
}

洛谷P1937 [USACO10MAR]Barn Allocation G

原文:https://www.cnblogs.com/lcezych/p/12995048.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!