F 题思路
题目意思:
给你一堆圣诞树,每个圣诞树在一个点 (xi,yi)(x_i,y_i)(xi,yi) 下面给出 222 种操作
- 单点修改 将第 iii 个圣诞树的点改为 (Xi,Yi)(X_i, Y_i)(Xi,Yi)
- 区间查询 给定 (L,R,Xi,Yi)(L, R, X_i, Y_i)(L,R,Xi,Yi) 查询区间 (L,R)(L, R)(L,R) 中和 (Xi,Yi)(X_i,Y_i)(Xi,Yi) 曼哈顿距离最短的圣诞树。
其中,两个点 (x1,y1)(x_1,y_1)(x1,y1) 和 (x2,y2)(x_2,y_2)(x2,y2) 的曼哈顿距离为 ∣x1−x2∣+∣y1−y2∣|x_1-x_2|+|y_1-y_2|∣x1−x2∣+∣y1−y2∣。
解法
使用线段树,我们设 区间查询 中距离和 (x1,y1)(x_1,y_1)(x1,y1) 最短的圣诞树的坐标为 (x,y)(x, y)(x,y).
那么查询的答案为 ans=∣x1−x∣+∣y1−y∣ans=|x_1-x|+|y_1-y|ans=∣x1−x∣+∣y1−y∣.
这个东西在线段树上面是不好维护的,我们考虑拆贡献.
强行拆掉绝对值符号,那么
ans=max{x1−x+y1−yx1−x−y1+y−x1+x+y1−y−x1+x−y1+y ans = \max \begin{cases} x_1-x+y_1-y \\ x_1-x-y_1+y \\ -x_1+x+y_1-y \\ -x_1+x-y_1+y \\ \end{cases} ans=max⎩ ⎨ ⎧x1−x+y1−yx1−x−y1+y−x1+x+y1−y−x1+x−y1+y
整理一下答案,得
ans=max{(x1+y1)−(x+y)(x1−y1)−(x−y)−(x1−y1)+(x−y)−(x1+y1)+(x+y) ans = \max \begin{cases} (x_1+y_1)-(x+y) \\ (x_1-y_1)-(x-y) \\ -(x_1-y_1)+(x-y) \\ -(x_1+y_1)+(x+y) \\ \end{cases} ans=max⎩ ⎨ ⎧(x1+y1)−(x+y)(x1−y1)−(x−y)−(x1−y1)+(x−y)−(x1+y1)+(x+y)
设 Ai=x1+y1A_i = x_1+y_1Ai=x1+y1 和 Bi=x1−y1B_i = x_1-y_1Bi=x1−y1
那么答案变为
ans=max{Ai−(x+y)Bi−(x−y)−Bi+(x−y)−Ai+(x+y) ans = \max \begin{cases} A_i-(x+y) \\ B_i-(x-y) \\ -B_i+(x-y) \\ -A_i+(x+y) \\ \end{cases} ans=max⎩ ⎨ ⎧Ai−(x+y)Bi−(x−y)−Bi+(x−y)−Ai+(x+y)
- 第 111 个式子 Ai−(x+y)A_i-(x+y)Ai−(x+y), 发现 AiA_iAi 越大式子越大.
- 第 222 个式子 Bi−(x−y)B_i-(x-y)Bi−(x−y), 发现 BiB_iBi 越大式子越大.
- 第 333 个式子, 发现 BiB_iBi 越小式子越大
- 第 444 个式子, 发现 AiA_iAi 越小式子越大
因为 (x+y)(x+y)(x+y) 和 (x−y)(x-y)(x−y) 是不变的
所以现在转换成了最大最小值查询问题, 可以使用线段树维护。
形式化的讲,现在具体需要维护的东西是:
- 每棵圣诞树 (x+y),(x−y)(x+y),(x-y)(x+y),(x−y) 的最大值.
- 每棵圣诞树 (x+y),(x−y)(x+y),(x-y)(x+y),(x−y) 的最小值.
所以直接是线段树模板题.
然后单次查询出来就是答案
Code\text{Code}Code
c
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
//#define DEBUG
#define int long long
#ifdef DEBUG
#define DBG printf
#else
#define DBG(...)
#endif
typedef struct {
int MaxAdd;
int MaxDiff;
int MinAdd;
int MinDiff;
}Node;
int max(int x, int y) {return x > y ? x : y;}
int min(int x, int y) {return x < y ? x : y;}
void swap(int* x, int* y) {int t = *x; *x = *y; *y = t;}
void copy(Node* x, Node y) {x->MaxAdd = y.MaxAdd, x->MaxDiff = y.MaxDiff, x->MinAdd = y.MinAdd, x->MinDiff = y.MinDiff;}
int InRange(int x, int y, int ck_val) {return (x <= ck_val && y >= ck_val);}
int IsRangeIns(int x1, int y1, int x2, int y2) {return !(y1 < x2 || x1 > y2);}
#define MAXN 400010
#define L (rt << 1)
#define R (rt << 1 | 1)
#define INF_MAX 0x3f3f3f3f3f3f3f3fLL
#define INF_MIN -INF_MAX
Node tree[MAXN << 2]; // 4 倍空间
int InputPos[MAXN][2]; // 输入的 X_i, Y_i
Node merge(Node p1, Node p2) {return (Node) {max(p1.MaxAdd, p2.MaxAdd), max(p1.MaxDiff, p2.MaxDiff), min(p1.MinAdd, p2.MinAdd), min(p1.MinDiff, p2.MinDiff)};}
void PushUp(int rt) {copy(&tree[rt], merge(tree[L], tree[R]));}
// 建树部分
void build(int rt, int uLeft, int uRight) {
if (uLeft == uRight) { // 叶子节点
int X = InputPos[uLeft][0], Y = InputPos[uLeft][1];
copy(&tree[rt], (Node) {X + Y, X - Y, X + Y, X - Y});
return ;
}
int mid = (uLeft + uRight) >> 1;
build(L, uLeft, mid), build(R, mid + 1, uRight);
PushUp(rt);
}
// 修改部分
void update(int rt, int rtLeft, int rtRight, int uPos, int X, int Y) {
if (rtLeft == rtRight) { // 叶子节点
copy(&tree[rt], (Node) {X + Y, X - Y, X + Y, X - Y});
return ;
}
int mid = (rtLeft + rtRight) >> 1;
if (uPos <= mid) update(L, rtLeft, mid, uPos, X, Y);
if (uPos > mid) update(R, mid + 1, rtRight, uPos, X, Y);
PushUp(rt);
}
// 查询部分
Node query(int rt, int rtLeft, int rtRight, int qLeft, int qRight) {
if (qLeft <= rtLeft && rtRight <= qRight) return tree[rt];
int mid = (rtLeft + rtRight) >> 1;
Node ans = (Node) {INF_MIN, INF_MIN, INF_MAX, INF_MAX};
if (qLeft <= mid) copy(&ans, query(L, rtLeft, mid, qLeft, qRight));
if (qRight > mid) copy(&ans, merge(ans, query(R, mid + 1, rtRight, qLeft, qRight)));
return ans;
}
int N, Q;
signed main()
{
// freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
scanf("%lld %lld", &N, &Q);
for (int i = 1; i <= N; i++) scanf("%lld %lld", &InputPos[i][0], &InputPos[i][1]);
build(1, 1, N);
DBG("Build Tree Time = %.3lfs", (clock() - p) * 1.0 / CLOCKS_PER_SEC);
while (Q --) {
int op;
scanf("%lld", &op);
if (op == 1) {
int pos, X, Y;
scanf("%lld %lld %lld", &pos, &X, &Y);
update(1, 1, N, pos, X, Y);
}
else {
int l, r, X, Y;
scanf("%lld %lld %lld %lld", &l, &r, &X, &Y);
Node ans;
copy(&ans, query(1, 1, N, l, r));
int res = -1e18;
res = max(res, ans.MaxAdd - (X + Y));
res = max(res, ans.MaxDiff - (X - Y));
res = max(res, -ans.MinDiff + (X - Y));
res = max(res, -ans.MinAdd + (X + Y));
printf("%lld\n", res);
}
}
return 0;
}
后记 and Update\text{后记 and Update}后记 and Update
- 创建日期: 2025-12-22