线段树 (ICPC小米预赛第二场 C Data Structure Problem)
Posted Kalzn
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线段树 (ICPC小米预赛第二场 C Data Structure Problem)相关的知识,希望对你有一定的参考价值。
题目链接
题意:给你一个两个序列
b
b
b和
a
a
a,序列
c
c
c由其生成,生成方式为:
c
0
=
0
,
c
i
=
m
a
x
c
i
−
1
+
b
i
,
a
i
c_0=0,c_i=max\\c_i-1+b_i,a_i\\
c0=0,ci=maxci−1+bi,ai
每次会对a、b进行单点修改,对c进行单点询问。
题解:首先如果不考虑a序列的影响。那么
c
i
=
∑
j
=
1
i
b
i
c_i=\\sum_j=1^ib_i
ci=∑j=1ibi此时我们考虑因为有些位置,
a
i
>
b
i
a_i>b_i
ai>bi所以,我们必须将答案在累计到“最高”的
a
i
a_i
ai,即最后有以下公式:
c
i
=
∑
j
=
1
i
b
j
+
m
a
x
0
,
m
a
x
1
≤
j
≤
i
a
j
−
∑
k
=
1
j
b
k
c_i=\\sum_j=1^ib_j+max\\0,max_1\\le j\\le i\\a_j-\\sum_k=1^jb_k\\\\
ci=j=1∑ibj+max0,max1≤j≤iaj−k=1∑jbk
线段树很容易就可以维护
b
b
b和
a
−
b
a-b
a−b序列的值。我们每查询
c
i
c_i
ci,首先查询
b
b
b的前缀和,然后在查询
[
1
,
i
]
[1,i]
[1,i]区间中
a
j
−
b
j
a_j-b_j
aj−bj的最大值,如果这个最大值小于0,答案即为
b
b
b的前缀和,否则答案即为
b
b
b的前缀和+这个最大值。(比赛的时候多亏了队友提了一嘴差值的事,QAQ。
下面是ac代码:
// % everyone
#include <cstdio>
#include<iostream>
#include<cstring>
#include <map>
#include <queue>
#include <set>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <vector>
#include <string>
#include <list>
#include <cctype>
#include <time.h>
namespace IO
double start_time = 0.0;
void ct() start_time = clock(); return;
void fast_cin() std::ios::sync_with_stdio(false); std::cin.tie();
void read_f(int flag = 0) freopen("0.in", "r", stdin); if(!flag) freopen("0.out", "w", stdout);
void run_time() std::cout << "\\nESC in : " << ( clock() - start_time ) * 1000.0 / CLOCKS_PER_SEC << "ms" << std::endl;
using namespace IO;
template <typename T>
bool bacmp(const T & a, const T & b) return a > b;
template <typename T>
bool pecmp(const T & a, const T & b) return a < b;
#define ll long long
#define ull unsigned ll
#define _min(x, y) ((x)>(y)?(y):(x))
#define _max(x, y) ((x)>(y)?(x):(y))
#define max3(x, y, z) ( max( (x), max( (y), (z) ) ) )
#define min3(x, y, z) ( min( (x), min( (y), (z) ) ) )
#define pr make_pair
#define pb push_back
#define int ll
using namespace std;
const int N = 2e5+6;
const int mod = 1e9+7;
const int inf = 0x3f3f3f3f;
ll a[N], b[N], b0[N];
struct Node
int l, r;
ll a, b, dif;
ll laz;
tr[N<<2];
void update(int p, int v)
tr[p].laz += v;
tr[p].b += v;
tr[p].dif -= v;
void spread(int p)
if (tr[p].laz == 0) return;
update(p<<1, tr[p].laz);
update(p<<1|1, tr[p].laz);
tr[p].laz = 0;
void pushup(int p)
tr[p].dif = max(tr[p<<1].dif, tr[p<<1|1].dif);
void build(int p, int l, int r)
tr[p].l = l; tr[p].r = r;
tr[p].laz = 0;
if (l == r)
tr[p].a = a[l];
tr[p].b = b[l];
tr[p].dif = a[l] - b[l];
return;
int mid = (l + r) >> 1;
build(p<<1, l, mid);
build(p<<1|1, mid+1, r);
pushup(p);
void changeb(int p, int l, int r, int v)
if (l <= tr[p].l && tr[p].r <= r)
update(p, v); return;
spread(p);
int mid = (tr[p].l + tr[p].r) >> 1;
if (l <= mid) changeb(p<<1, l, r, v);
if (r > mid) changeb(p<<1|1, l, r, v);
pushup(p);
void changea(int p, int pos, int v)
if (tr[p].l == tr[p].r)
tr[p].a += v;
tr[p].dif += v;
return;
spread(p);
int mid = (tr[p].l + tr[p].r) >> 1;
if (pos <= mid) changea(p<<1, pos, v);
else changea(p<<1|1, pos, v);
pushup(p);
ll askb(int p, int x)
if (tr[p].l == tr[p].r)
return tr[p].b;
int mid = (tr[p].l + tr[p].r) >> 1;
spread(p);
if (x <= mid) return askb(p<<1, x);
else return askb(p<<1|1, x);
ll askdif(int p, int l, int r)
if (l <= tr[p].l && tr[p].r <= r)
return tr[p].dif;
int mid = (tr[p].l + tr[p].r) >> 1;
spread(p);
ll val = -1ll * inf * inf;
if (l <= mid) val = askdif(p<<1, l, r);
if (r > mid) val = max(val, askdif(p<<1|1, l, r));
return val;
signed main()
int n, m;
while(~scanf("%lld%lld", &n, &m))
for (int i = 1; i <= n; i++)
scanf("%lld", &a[i]);
for (int i = 1; i <= n; i++)
scanf("%lld", &b[i]), b0[i] = b[i], b[i] +=b[i-1];
build(1, 1, n);
while(m--)
int op, x, y;
scanf("%lld%lld", &op, &x);
if (op == 3)
ll g = askb(1, x);
ll dif = max(0ll, askdif(1, 1, x));
printf("%lld\\n", g+dif);
else if (op == 1)
scanfICPC网络赛第二场 L.Euler Function 欧拉函数性质+势能线段树
ICPC网络赛第二场 L.Euler Function 欧拉函数性质+势能线段树
ACM-ICPC 2018 南京赛区网络预赛 Lpl and Energy-saving Lamps 线段树
ACM-ICPC 2018 南京赛区网络预赛 G Lpl and Energy-saving Lamps(线段树)