
考虑线段树维护一个区间[l,r]的代价和sum,离l最近的关键点的权值val,区间中每个点到其最右侧关键点的距离和
对于一个点来说,他的权值为 它左侧最近的关键点的权值val * 它到它右侧最近的关键点的距离dis
对于一个不包含关键点的区间[l,r],这个区间的权值为
而假设我们要在这个区间中的某个点x插入一个关键点
那么对于其左边的区间[l,x-1],这个区间的关键点权值val不变,而距离会减去
对于其右侧的区间[x+1,r],这个区间的距离不变,而关键点的权值val会变成val[x]
对于x这个点本身,将他的代价和,权值,距离都更新为0即可
cpp
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define lc p << 1
#define rc p << 1 | 1
int n, m, q;
const int N = 3e5 + 5;
int w[N];
set<int> s;
int val[N];
struct node
{
int l, r;
int dis, val, sum, lazyval, lazydis;
} tr[N * 4];
void pushup(int p)
{
tr[p].dis = tr[lc].dis + tr[rc].dis;
tr[p].sum = tr[lc].sum + tr[rc].sum;
tr[p].val = tr[lc].val;
}
void pushdown(int p)
{
if (tr[p].lazyval || tr[p].lazydis)
{
if (tr[p].lazyval)
{
tr[lc].val = tr[p].lazyval;
tr[rc].val = tr[p].lazyval;
tr[lc].lazyval = tr[p].lazyval;
tr[rc].lazyval = tr[p].lazyval;
tr[p].lazyval = 0;
}
if (tr[p].lazydis)
{
tr[lc].dis -= (tr[lc].r - tr[lc].l + 1) * tr[p].lazydis;
tr[rc].dis -= (tr[rc].r - tr[rc].l + 1) * tr[p].lazydis;
tr[lc].lazydis += tr[p].lazydis;
tr[rc].lazydis += tr[p].lazydis;
tr[p].lazydis = 0;
}
tr[lc].sum = tr[lc].val * tr[lc].dis;
tr[rc].sum = tr[rc].val * tr[rc].dis;
}
}
void build(int p, int l, int r)
{
tr[p] = {l, r, 0, 0, 0, 0, 0};
if (l == r)
{
auto nex = s.lower_bound(l);
if (*nex == l)
return;
auto pre = nex;
pre--;
tr[p].val = val[*pre];
tr[p].dis = *nex - l;
tr[p].sum = tr[p].val * tr[p].dis;
return;
}
int mid = l + r >> 1;
build(lc, l, mid);
build(rc, mid + 1, r);
pushup(p);
}
void updateval(int p, int x, int y, int k)
{
if (tr[p].l >= x && tr[p].r <= y)
{
tr[p].val = k;
tr[p].lazyval = k;
tr[p].sum = tr[p].dis * tr[p].val;
return;
}
int mid = tr[p].l + tr[p].r >> 1;
pushdown(p);
if (mid >= x)
updateval(lc, x, y, k);
if (mid < y)
updateval(rc, x, y, k);
pushup(p);
}
void updatedis(int p, int x, int y, int k)
{
if (tr[p].l >= x && tr[p].r <= y)
{
tr[p].lazydis += k;
tr[p].dis -= k * (tr[p].r - tr[p].l + 1);
tr[p].sum = tr[p].dis * tr[p].val;
return;
}
int mid = tr[p].l + tr[p].r >> 1;
pushdown(p);
if (mid >= x)
updatedis(lc, x, y, k);
if (mid < y)
updatedis(rc, x, y, k);
pushup(p);
}
void update(int p, int x)
{
if (tr[p].l == tr[p].r && tr[p].l == x)
{
tr[p] = {x, x, 0, 0, 0, 0, 0};
return;
}
int mid = tr[p].l + tr[p].r >> 1;
pushdown(p);
if (mid >= x)
update(lc, x);
else
update(rc, x);
pushup(p);
}
int query(int p, int x, int y)
{
if (tr[p].l >= x && tr[p].r <= y)
{
return tr[p].sum;
}
int mid = tr[p].l + tr[p].r >> 1;
int sum = 0;
pushdown(p);
if (mid >= x)
sum += query(lc, x, y);
if (mid < y)
sum += query(rc, x, y);
pushup(p);
return sum;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n >> m >> q;
vector<int> X(m + 1);
for (int i = 1; i <= m; i++)
cin >> X[i], s.insert(X[i]);
for (int i = 1; i <= m; i++)
cin >> val[X[i]];
build(1, 1, n);
while (q--)
{
int opt;
cin >> opt;
if (opt == 1)
{
int x, v;
cin >> x >> v;
val[x] = v;
s.insert(x);
auto it = s.find(x);
auto pre = it, nex = it;
pre--, nex++;
int pe = *pre, nx = *nex;
if (x - 1 >= pe + 1)
updatedis(1, pe + 1, x - 1, nx - x);
if (nx - 1 >= x + 1)
updateval(1, x + 1, nx - 1, v);
update(1, x);
}
else
{
int l, r;
cin >> l >> r;
cout << query(1, l, r) << endl;
}
}
}