• [做题记录-数据结构] 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;
    }
    
  • 相关阅读:
    实体类调用泛型父类中的静态方法中执行CRUD——第一版
    Windows10 磁盘100%解决办法
    Torchvision 源码安装[Ubuntu]
    Pycharm调试:进入调用函数后返回
    Windows 10 家庭版/专业版 彻底关闭windows update自动更新
    Windows10 家庭版 关闭Windows defender
    Windows 10 更改系统文字大小
    Ubuntu 使用命令行连接无线网
    支持向量机(SVM)
    Ubuntu系统实现将Jupyter notebook项目发布到GitHub
  • 原文地址:https://www.cnblogs.com/clover4/p/15269051.html
Copyright © 2020-2023  润新知