ACM-ICPC 2018 徐州赛区网络预赛 H. Ryuji doesn’t want to study
标签
- 线段树
- 带权查询
简明题意
- 给一个序列,需要支持两种操作:
- 查询:查询L-R区间, a [ l ] × L + a [ l + 1 ] × ( L − 1 ) + ⋯ + a [ r − 1 ] × 2 + a [ r ] a[l]×L+a[l+1]×(L−1)+⋯+a[r−1]×2+a[r] a[l]×L+a[l+1]×(L−1)+⋯+a[r−1]×2+a[r],其中L定义为查询的区间的长度
- 修改:将某个值修改为x
思路
- 查询的元素带权了,权值跟所查的右端点相关。怎么办呢。我的做法是线段树维护两种信息,一个是L-R的和,另一个是,从1开始每个元素的n-r+1倍的和,这样维护的话,我们区间查询,比如区间长度是6,查询3-5,用维护的第二种信息查询出来是 4 ∗ a [ 3 ] + 3 ∗ a [ 4 ] + 2 ∗ a [ 5 ] 4*a[3]+3*a[4]+2*a[5] 4∗a[3]+3∗a[4]+2∗a[5],维护的第一种信息查询出来是 a [ 3 ] + a [ 4 ] + a [ 5 ] a[3]+a[4]+a[5] a[3]+a[4]+a[5],将这两个直接相减就得到了想要的答案。当然,如果查询的区间不同,维护的第二种信息的右端点的倍数不一样,减去的值也应该是第一种信息的若干倍
注意事项
- 无
总结
- 带权查询有的时候可以多维护一种信息,从而得到正确的关系
AC代码
#include<cstdio>
#include<algorithm>
using namespace std;
const long long maxn = 1e5 + 10;
long long n, m, a[maxn];
struct Node
{
long long l, r;
long long sum_j, sum_single;
};
Node tree[maxn * 4];
void update(long long o)
{
if (tree[o].l != tree[o].r)
{
tree[o].sum_j = tree[o * 2].sum_j + tree[o * 2 + 1].sum_j;
tree[o].sum_single = tree[o * 2].sum_single + tree[o * 2 + 1].sum_single;
}
}
void build(long long o, long long l, long long r)
{
tree[o].l = l, tree[o].r = r;
if (l == r)
{
tree[o].sum_single = a[l];
tree[o].sum_j = (n - r + 1) * a[l];
return;
}
long long mid = (l + r) / 2;
build(o * 2, l, mid);
build(o * 2 + 1, mid + 1, r);
update(o);
}
long long ask(long long o, long long l, long long r, long long k)
{
if (tree[o].l == l && tree[o].r == r)
return tree[o].sum_j - k * tree[o].sum_single;
long long mid = (tree[o].l + tree[o].r) / 2;
if (r <= mid)
return ask(o * 2, l, r, k);
else if (l > mid)
return ask(o * 2 + 1, l, r, k);
else
return ask(o * 2, l, mid, k) + ask(o * 2 + 1, mid + 1, r, k);
}
void change(long long o, long long x, long long c)
{
if (tree[o].l == tree[o].r)
{
tree[o].sum_single = c;
tree[o].sum_j = (n - tree[o].r + 1) * c;
return;
}
long long mid = (tree[o].l + tree[o].r) / 2;
if (x <= mid)
change(o * 2, x, c);
else
change(o * 2 + 1, x, c);
update(o);
}
void solve()
{
scanf("%lld%lld", &n, &m);
for (long long i = 1; i <= n; i++)
scanf("%lld", &a[i]);
build(1, 1, n);
while (m--)
{
long long opt;
scanf("%lld", &opt);
if (opt == 1)
{
long long l, r;
scanf("%lld%lld", &l, &r);
printf("%lld\n", ask(1, l, r, n - r));
}
else
{
long long x, c;
scanf("%lld%lld", &x, &c);
change(1, x, c);
}
}
}
int main()
{
freopen("Testin.txt", "r", stdin);
solve();
return 0;
}
双倍经验
- 无