UOJ#410. 【IOI2018】会议

传送门
首先可以设 f [ l ] [ r ] f[l][r] f[l][r] 表示 [ l , r ] [l,r] [l,r] 的答案
x x x 为区间 [ l , r ] [l,r] [l,r] 的最大值的位置,那么
f [ l ] [ r ] = m i n ( f [ l ] [ x − 1 ] + h [ x ] × ( r − x + 1 ) , f [ x + 1 ] [ r ] + h [ x ] × ( x − l + 1 ) ) f[l][r] = min(f[l][x-1]+h[x]\times (r-x+1),f[x+1][r]+h[x]\times (x-l+1)) f[l][r]=min(f[l][x1]+h[x]×(rx+1),f[x+1][r]+h[x]×(xl+1))
这样的 d p dp dp 结构形成了笛卡尔树
那么考虑在笛卡尔树上维护 d p dp dp
对于笛卡尔树上的一个点 x x x 它有一个区间 [ l , r ] [l,r] [l,r],考虑维护 f [ l ] [ i ] f[l][i] f[l][i] f [ i ] [ r ] , i ∈ [ l , r ] f[i][r],i\in [l,r] f[i][r],i[l,r]
对于固定左端点的 f [ l ] [ i ] f[l][i] f[l][i]( f [ i ] [ r ] f[i][r] f[i][r] 类似)
1首先可以由 x x x 在笛卡尔树的左儿子继承,即 i &lt; x i&lt;x i<x
2 i = x i=x i=x 那么 f [ l ] [ x ] = f [ l ] [ x − 1 ] + h [ x ] f[l][x]=f[l][x-1]+h[x] f[l][x]=f[l][x1]+h[x]
3 i &gt; x i&gt;x i>x 那么 f [ l ] [ i ] = m i n ( f [ l ] [ x − 1 ] + h [ x ] × ( i − x + 1 ) , f [ x + 1 ] [ i ] + h [ x ] × ( x − l + 1 ) ) f[l][i]=min(f[l][x-1]+h[x]\times (i-x+1),f[x+1][i]+h[x]\times (x-l+1)) f[l][i]=min(f[l][x1]+h[x]×(ix+1),f[x+1][i]+h[x]×(xl+1))
前两个好办,对于3,可以证明,这个 m i n min min 的函数是存在一个分界点,使得在左边一个更优,而右边另一个最优,并且具有可二分性
证明
只需要证明下面的东西即可
f [ l ] [ x − 1 ] + ( i − x + 1 ) × h [ x ] − ( f [ x + 1 ] [ i ] + ( x − l + 1 ) × h [ x ] ) ( ≥ ) ≤ f [ l ] [ x − 1 ] + ( ( i + 1 ) − x + 1 ) × h [ x ] − ( f [ x + 1 ] [ i + 1 ] + ( x − l + 1 ) × h [ x ] ) f[l][x-1]+(i-x+1)\times h[x]-(f[x+1][i]+(x-l+1)\times h[x])(\ge)\le\\ f[l][x-1]+((i+1)-x+1)\times h[x]-(f[x+1][i+1]+(x-l+1)\times h[x]) f[l][x1]+(ix+1)×h[x](f[x+1][i]+(xl+1)×h[x])()f[l][x1]+((i+1)x+1)×h[x](f[x+1][i+1]+(xl+1)×h[x])
因为
f [ x + 1 ] [ i + 1 ] − f [ x + 1 ] [ i ] ≤ h [ x ] f[x+1][i+1]-f[x+1][i]\le h[x] f[x+1][i+1]f[x+1][i]h[x]
那么可以证明上式取 ≤ \le
那么直接二分端点就好了
现在只需要支持区间加,区间对等差数列取 m i n min 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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值