前言
估计大家可能被点的权值(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×n−3 的点边集(再乘个二是因为我们要拆一个环), 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 2−inf4−inf3−inf3−inf4
\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;
}
完结撒花✿✿ヽ(°▽°)ノ✿