P6309 题解
很经典但是很好的题目。/qiang
标签:线段树。
- 数轴上有一些关键点,不同的关键点可能在同一坐标。关键点的坐标均为整数。
- 支持两种操作:
- 删去 / 添加一些关键点。
- 取一个点。使得它与
范围内所有关键点的距离最小。求最小距离。 , 。
首先每个坐标上有多少个关键点是很好维护的。如果已经取了个点,如何计算答案?一个经典做法是把绝对值拆开。假设取的点坐标是
问题来到了如何找点
用权值线段树维护即可。时间复杂度
#include <iostream>
#include <cstdio>
using namespace std;
typedef long long ll;
const int N = 300010, eps = 1e9, V = 1e9;
int cnt, ro;
struct Seg {
int ls, rs;
ll c, v;
} T[N * 4 * 32];
int n, m; ll a[N], b[N];
#define ls(k) (T[k].ls)
#define rs(k) (T[k].rs)
inline int read() {
int x = 0, f = 1;
char c = getchar();
while (!isdigit(c)) {if (c == '-') f = -1; c = getchar();}
while (isdigit(c)) x = x * 10 + c - 48, c = getchar();
return x * f;
}
inline void write(ll x) {
if (x > 9) write(x / 10);
putchar(x % 10 + 48);
}
void pushup(int k) {
T[k].c = T[ls(k)].c + T[rs(k)].c;
T[k].v = T[ls(k)].v + T[rs(k)].v;
}
void update(ll l, ll r, int &k, ll x, ll c) {
if(!k) k = ++cnt;
if(l == r) {
T[k].c += c;
T[k].v = x * T[k].c;
return;
}
ll mid = (l + r) / 2;
if(x <= mid) update(l, mid, ls(k), x, c);
else update(mid + 1, r, rs(k), x, c);
pushup(k);
}
ll getc(ll l, ll r, int k, ll L, ll R) {
if(!k) return 0;
if(L <= l && r <= R) return T[k].c;
ll mid = (l + r) / 2, res = 0;
if(L <= mid) res += getc(l, mid, ls(k), L, R);
if(mid < R) res += getc(mid + 1, r, rs(k), L, R);
return res;
}
ll getv(ll l, ll r, int k, ll L, ll R) {
if(!k) return 0;
if(L <= l && r <= R) return T[k].v;
ll mid = (l + r) / 2, res = 0;
if(L <= mid) res += getv(l, mid, ls(k), L, R);
if(mid < R) res += getv(mid + 1, r, rs(k), L, R);
return res;
}
ll find(ll l, ll r, int k, ll c) {
if(l == r) return l;
int mid = (l + r) / 2;
if(c <= T[ls(k)].c) return find(l, mid, ls(k), c);
else return find(mid + 1, r, rs(k), c - T[ls(k)].c);
}
int main() {
// ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
n = read(), m = read();
for (int i = 1; i <= n; i++) a[i] = read() + eps;
for (int i = 1; i <= n; i++) {
b[i] = read();
update(0, 2e9, ro, a[i], b[i]);
}
while(m--) {
int op = read();
if(op == 2) {
ll x = read(), y = read() + eps, z = read();
update(0, 2e9, ro, a[x], -b[x]);
a[x] = y, b[x] = z;
update(0, 2e9, ro, a[x], b[x]);
} else {
ll l = read() + eps, r = read() + eps;
ll mid = getc(0, 2e9, ro, 0, l - 1) + (getc(0, 2e9, ro, l, r) + 1) / 2;
mid = find(0, 2e9, ro, mid);
write(mid * getc(0, 2e9, ro, l, mid - 1) - getv(0, 2e9, ro, l, mid - 1) + getv(0, 2e9, ro, mid + 1, r) - mid * getc(0, 2e9, ro, mid + 1, r));
puts("");
}
}
return 0;
}
如有错误烦请您指出。
本文作者:Running-a-way
本文链接:https://www.cnblogs.com/Running-a-way/p/18455220
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步