• UOJ#410. 【IOI2018】会议


    传送门
    首先可以设 (f[l][r]) 表示 ([l,r]) 的答案
    (x) 为区间 ([l,r]) 的最大值的位置,那么
    (f[l][r] = min(f[l][x-1]+h[x] imes (r-x+1),f[x+1][r]+h[x] imes (x-l+1)))
    这样的 (dp) 结构形成了笛卡尔树
    那么考虑在笛卡尔树上维护 (dp)
    对于笛卡尔树上的一个点 (x) 它有一个区间 ([l,r]),考虑维护 (f[l][i])(f[i][r],iin [l,r])
    对于固定左端点的 (f[l][i])((f[i][r]) 类似)
    1首先可以由 (x) 在笛卡尔树的左儿子继承,即 (i<x)
    2(i=x) 那么 (f[l][x]=f[l][x-1]+h[x])
    3(i>x) 那么 (f[l][i]=min(f[l][x-1]+h[x] imes (i-x+1),f[x+1][i]+h[x] imes (x-l+1)))
    前两个好办,对于3,可以证明,这个 (min) 的函数是存在一个分界点,使得在左边一个更优,而右边另一个最优,并且具有可二分性
    证明
    只需要证明下面的东西即可
    (f[l][x-1]+(i-x+1) imes h[x]-(f[x+1][i]+(x-l+1) imes h[x])(ge)le\ f[l][x-1]+((i+1)-x+1) imes h[x]-(f[x+1][i+1]+(x-l+1) imes h[x]))
    因为
    (f[x+1][i+1]-f[x+1][i]le h[x])
    那么可以证明上式取 (le)
    那么直接二分端点就好了
    现在只需要支持区间加,区间对等差数列取 (min),单点询问这些操作
    可以离线线段树统计答案或者主席树在线回答

    # include "meetings.h"
    # include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    const int maxn(7.5e5 + 5);
    
    struct Segment {
    	ll covk[maxn << 2], covb[maxn << 2], add[maxn << 2], vl[maxn << 2], vr[maxn << 2];
    	int cov[maxn << 2];
    
    	inline void Cover(int x, int l, int r, ll k, ll b) {
    		cov[x] = 1, add[x] = 0, vl[x] = k * l + b, vr[x] = k * r + b, covk[x] = k, covb[x] = b;
    	}
    
    	inline void Addv(int x, ll v) {
    		add[x] += v, vl[x] += v, vr[x] += v;
    	}
    
    	inline void Pushdown(int x, int l, int mid, int r) {
    		if (cov[x]) {
    			Cover(x << 1, l, mid, covk[x], covb[x]);
    			Cover(x << 1 | 1, mid + 1, r, covk[x], covb[x]);
    			cov[x] = 0;
    		}
    		if (add[x]) Addv(x << 1, add[x]), Addv(x << 1 | 1, add[x]), add[x] = 0;
    	}
    
    	ll Query(int x, int l, int r, int p) {
    		if (l == r) return vl[x];
    		int mid = (l + r) >> 1;
    		Pushdown(x, l, mid, r);
    		ll ret = (p <= mid ? Query(x << 1, l, mid, p) : Query(x << 1 | 1, mid + 1, r, p));
    		vl[x] = vl[x << 1], vr[x] = vr[x << 1 | 1];
    		return ret;
    	}
    
    	void Chkmin(int x, int l, int r, int ql, int qr, ll k, ll b, ll v) {
    		if (ql <= l && qr >= r) {
    			if (k * r + b <= vr[x] + v && k * l + b <= vl[x] + v) {
    			    Cover(x, l, r, k, b);
    				return;
    			}
    			if (k * l + b >= vl[x] + v && k * r + b >= vr[x] + v) {
    				Addv(x, v);
    				return;
    			}
    		}
    		int mid = (l + r) >> 1;
    		Pushdown(x, l, mid, r);
    		if (ql <= mid) Chkmin(x << 1, l, mid, ql, qr, k, b, v);
    		if (qr > mid) Chkmin(x << 1 | 1, mid + 1, r, ql, qr, k, b, v);
    		vl[x] = vl[x << 1], vr[x] = vr[x << 1 | 1];
    	}
    } fix_l, fix_r;
    
    int q, n, h[maxn], st[20][maxn], lg[maxn], qryl[maxn], qryr[maxn];
    vector <ll> ans;
    vector <int> qry[maxn];
    
    inline int Max(int x, int y) {
    	return h[x] > h[y] ? x : y;
    }
    
    inline int RMQ(int l, int r) {
    	int len = lg[r - l + 1];
    	return Max(st[len][l], st[len][r - (1 << len) + 1]);
    }
    
    void Solve(int l, int r) {
    	if (l > r) return;
    	int mid = RMQ(l, r), i, len = qry[mid].size(), id;
    	ll fl = 0, fr = 0;
    	Solve(l, mid - 1), Solve(mid + 1, r);
    	for (i = 0; i < len; ++i) {
    		id = qry[mid][i];
    		ans[id] = (ll)h[mid] * (qryr[id] - qryl[id] + 1);
    		if (qryl[id] < mid) ans[id] = min(ans[id], (ll)(qryr[id] - mid + 1) * h[mid] + fix_r.Query(1, 1, n, qryl[id]));
    		if (qryr[id] > mid) ans[id] = min(ans[id], (ll)(mid - qryl[id] + 1) * h[mid] + fix_l.Query(1, 1, n, qryr[id]));
    	}
    	if (l < mid) fl = fix_r.Query(1, 1, n, l);
    	if (r > mid) fr = fix_l.Query(1, 1, n, r);
    	fix_r.Chkmin(1, 1, n, l, mid, -h[mid], fr + (ll)h[mid] * (mid + 1), (ll)h[mid] * (r - mid + 1));
    	fix_l.Chkmin(1, 1, n, mid, r, h[mid], fl - (ll)h[mid] * (mid - 1), (ll)h[mid] * (mid - l + 1));
    }
    
    vector <ll> minimum_costs(vector <int> _h, vector <int> _l, vector <int> _r) {
    	int i, j, mid;
    	q = _l.size(), n = _h.size();
    	for (i = 0; i < n; ++i) st[0][i + 1] = i + 1, h[i + 1] = _h[i];
    	for (i = 2; i <= n; ++i) lg[i] = lg[i >> 1] + 1;
    	for (j = 1; j <= lg[n]; ++j)
    		for (i = 1; i + (1 << j) - 1 <= n; ++i)
    			st[j][i] = Max(st[j - 1][i], st[j - 1][i + (1 << (j - 1))]);
    	ans.resize(q);
    	for (i = 0; i < q; ++i) {
    		mid = RMQ(_l[i] + 1, _r[i] + 1);
    		qry[mid].push_back(i);
    		qryl[i] = _l[i] + 1, qryr[i] = _r[i] + 1;
    	}
    	Solve(1, n);
    	return ans;
    }
    
  • 相关阅读:
    C#编程技巧之钩子函数的使用——SetWindowsHookEx
    JSON(Ajax)和JsonP
    C#对象与方法
    C#数据类型
    事务处理
    面向对象之继承与多态
    C#编程语言简介
    <转>成员函数的重载、覆盖与隐藏
    视图、索引
    C#方法
  • 原文地址:https://www.cnblogs.com/cjoieryl/p/10345049.html
Copyright © 2020-2023  润新知