题解 CF515E 【Drazil and Park】

前言

估计大家可能被点的权值(h)和边的长度(d)两者的维护卡了好久。我们可以来一次简单的转换,使复杂的数据变得简单。

Main Tips

不妨把边长看成一个点,它拥有权值 d i d_i di ,那么相对应的原先的点也获得一个权值 d i = 0 d_i = 0 di=0为了不让边完全成为一个“点”我们将它的 h i h_i hi 设为 -inf,保证不是从边进入或出来。再用线段树维护一条 4 × n − 3 4 \times n - 3 4×n3 的点边集(再乘个二是因为我们要拆一个环) l _ v a l l\_val l_val r _ v a l r\_val r_val n o _ v a l no\_val no_val t w o _ v a l two\_val two_val 分别表示只有左端有 h i h_i hi ,只有右端有 $h_i $,两端都无和两端都有。现在,它就变成了一道经典的线段树维护两端点权值 + 端点间距离的题目了。最后 query 一下就 OK 啦!

举个栗子:

h i : h_i: hi: 2 \qquad\quad 4 3 2 4 \qquad\quad 3 \quad\qquad 2\quad\qquad 4 324

     \quad\,\,\,\, 1 − − > --> > 2 − − > --> > 3 − − > --> > 1 − − > --> > 2

d i : d_i: di: 2 2 3 2 \quad\quad 2\quad\qquad 2 \quad\qquad 3 \quad\quad\quad 2 2232

上面是点权,下面边权,中间是编号。它现在变成惹 − − > --> >

h i : h_i: hi: 2 − i n f 4 − i n f      3 − i n f 3 − i n f 4 2\quad -inf\qquad 4\quad-inf\quad\,\,\,\,3\quad-inf\qquad 3\quad-inf\qquad 4 2inf4inf3inf3inf4

     \quad\,\,\,\, 1 − − > --> > 2 − − > --> > 3 − − > --> > 4 − − > --> > 5 − − > --> > 6 − − > --> > 7 − − > --> > 8 − − > --> > 9

d i : d_i: di:    0    2 0 2 0 3 0 2 0 \,\, 0\qquad\,\, 2\qquad\quad 0\qquad 2\quad\qquad0\qquad\quad 3\qquad 0\qquad\quad 2\qquad 0 020203020

上面是更改后的点权,下面是更改后的边权,中间是更改后的编号。最后的答案就是 t w o _ a n s two\_ans two_ans (两端都有 h i h_i hi)。目前为最优解 rank2 。

Code

#include <cstdio>
#include <cctype>
#include <algorithm>
#define ll long long
#define inf 10000000000000000

using namespace std;

inline ll read(){
	ll x=0,w=0;char ch=getchar();
	while (!isdigit(ch))w|=ch=='-',ch=getchar();
	while (isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
	return w?-x:x;
}

struct node{
	ll two_val, l_val, r_val, no_val;
}a[8000005];

ll n, m, h[800005], dis[800005], two_ans, l_ans, r_ans, no_ans;

inline ll ls(ll p){
	return p << 1;
}

inline ll rs(ll p){
	return p << 1 | 1;
}

inline void update(int p){
	a[p].two_val = max(a[ls(p)].l_val + a[rs(p)].r_val, max(a[ls(p)].two_val , a[rs(p)].two_val ));
	a[p].l_val = max(a[ls(p)].l_val + a[rs(p)].no_val, a[rs(p)].l_val ) ;
	a[p].r_val = max(a[ls(p)].no_val + a[rs(p)].r_val, a[ls(p)].r_val ) ;
	a[p].no_val = a[ls(p)].no_val + a[rs(p)].no_val ;
}

inline void build(ll p, ll l, ll r){
	if(l == r){
		a[p].l_val = h[l] + dis[l];
		a[p].r_val = h[l] + dis[l];
		a[p].no_val = dis[l];
		return ;
	}
	ll mid = l + r >> 1;
	build(ls(p), l, mid);
	build(rs(p), mid + 1, r);
	update(p);
}

inline ll query(ll p, ll l, ll r, ll L, ll R){
	if(L <= l && r <= R){
		two_ans = max(two_ans, max(a[p].two_val , l_ans + a[p].r_val ));
		l_ans = max(l_ans + a[p].no_val , max(a[p].l_val , l_ans));
		return 0;
	}
	ll mid = l + r >> 1;
	if(mid >= L) query(ls(p), l, mid, L, R);
	if(mid < R) query(rs(p), mid + 1, r, L, R);
}

int main(){
	n = read();
	m = read();
	for(int i = 2; i <= 2 * n; i += 2)
	dis[i] = read(), dis[i - 1] = 0;
	for(int i = 1; i <= 2 * n; i += 2)
	h[i] = read() * 2, h[i + 1] = -inf;
	for(int i = 1; i <= 2 * n; i++)
	dis[2 * n + i] = dis[i], h[i + 2 * n] = h[i];
	build(1, 1, 4 * n - 1);
	for(int i = 1; i <= m; i++){
		ll x = read(), y = read();
		two_ans = l_ans = -inf;
		if(x == y){
			query(1, 1, 4 * n - 1, 2 * x + 1, 2 * x - 3 + 2 * n);
		}
		else if(x < y){
			query(1, 1, 4 * n - 1, 2 * y + 1, 2 * x - 3 + 2 * n);
		}
		else {
			query(1 , 1, 4 * n - 1, 2 * y + 1, 2 * x - 3);
		}
		printf("%lld\n",two_ans);
	}
    return 0;
}

完结撒花✿✿ヽ(°▽°)ノ✿

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值