[做题记录-数据结构] Loj 3523. 「IOI2021」分糖果

题面

Problem Link
\(n\)个盒子\(m\)个操作, 每个盒子有一个上限。每次的操作是区间加减一个数且超过上限的不算低于\(0\)的不算。求最后的结果。

题解

考虑这样一个搞法, 扫描线扫序列, 然后区间修改变单点, 用一个时间上的线段树维护每个时间的修改的时间后缀和, 那么考虑求答案。
可以在线段树上二分出最靠后的\(mx - mn > c\)的点, 如果顶了上下界, 这样就会二分出倒数第二次的顶上界时间, 讨论一下就可以得到答案。如果没有顶上下界的话直接使用\(mx - mn\)即可得到答案。

#include "candies.h"

#include<bits/stdc++.h>
using namespace std;

using ll = long long;
using vint = vector<int>;

ll S;
int n, m;
const int N = 2e5 + 10;
vector<pair<int, int> > Q[N];

struct Node {
	Node *ls, *rs;
	int l, r;
	ll mn, mx, tag;
	Node() {}
	Node(int _l, int _r) : l(_l), r(_r), mn(0), mx(0) , tag(0) { ls = rs = NULL; }
	void upd() {
		mn = min(ls -> mn, rs -> mn);
		mx = max(ls -> mx, rs -> mx);
	}
	void pushtag(ll v) {
		mn += v; mx += v; tag += v;
	}
	void pushdown() {
		if(tag) {
			ls -> pushtag(tag);
			rs -> pushtag(tag);
			tag = 0;
		}
	}
	void modify(int L, int R, ll v) {
		if(L <= l && r <= R) {
			this -> pushtag(v);
			return ;
		}
		this -> pushdown();
		int mid = (l + r) >> 1;
		if(L <= mid) ls -> modify(L, R, v);
		if(R > mid) rs -> modify(L, R, v);
		this -> upd();
	}
	int query(int L, int R, int C, ll mnv, ll mxv) {
		if(l == r) {
			if(this -> mx > S) return S - mnv;
			return C - (mxv - S);
		}
		this -> pushdown();
		int mid = (l + r) >> 1;
		ll tmin = min(mnv, rs -> mn);
		ll tmax = max(mxv, rs -> mx);
		if(tmax - tmin <= C) return ls -> query(L, R, C, tmin, tmax);
		else return rs -> query(L, R, C, mnv, mxv);
	}
} ;

Node *rt;

Node *build(int l, int r) {
	Node * x = new Node(l, r);
	if(l == r) return x;
	int mid = (l + r) >> 1;
	x -> ls = build(l, mid);
	x -> rs = build(mid + 1, r);
	x -> upd();
	return x;
}

vint distribute_candies(vint c, vint l, vint r, vint v) {
	n = c.size();
	m = l.size();
	vint ans; ans.resize(n);
	for(int i = 0; i < m; i ++) 
		Q[l[i]].push_back({i, v[i]}), 
		Q[r[i] + 1].push_back({i, -v[i]});
	rt = build(0, m);
	for(int i = 0; i < n; i ++) {
		for(auto p : Q[i]) S += p.second, rt -> modify(p.first + 1, m, p.second);
		if (rt -> mx - rt -> mn <= c[i])
            ans[i] = S - rt -> mn;
        else
            ans[i] = rt -> query(0, m, c[i], 0x3f3f3f3f3f3f3f3fLL, -0x3f3f3f3f3f3f3f3fLL);
	}
    return ans;
}
posted @ 2021-09-14 18:37  HN-wrp  阅读(69)  评论(0编辑  收藏  举报