• 洛谷P1937 [USACO10MAR]Barn Allocation G


    题意:
    洛谷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;
    }
    
  • 相关阅读:
    会议记录-5月20日
    会议记录-5月19日
    会议记录—5月18日
    会议记录-5月17日
    会议记录-5月16日
    会议记录-5月13日
    团队博客
    学习进度总结
    校外实习总结
    校外实习报告(二十)
  • 原文地址:https://www.cnblogs.com/lcezych/p/12995048.html
Copyright © 2020-2023  润新知