BZOJ 2157 旅游 (树链剖分)

                                                     2157: 旅游

Description

Ray 乐忠于旅游,这次他来到了T 城。T 城是一个水上城市,一共有 N 个景点,有些景点之间会用一座桥连接。为了方便游客到达每个景点但又为了节约成本,T 城的任意两个景点之间有且只有一条路径。换句话说, T 城中只有N − 1 座桥。Ray 发现,有些桥上可以看到美丽的景色,让人心情愉悦,但有些桥狭窄泥泞,令人烦躁。于是,他给每座桥定义一个愉悦度w,也就是说,Ray 经过这座桥会增加w 的愉悦度,这或许是正的也可能是负的。有时,Ray 看待同一座桥的心情也会发生改变。现在,Ray 想让你帮他计算从u 景点到v 景点能获得的总愉悦度。有时,他还想知道某段路上最美丽的桥所提供的最大愉悦度,或是某段路上最糟糕的一座桥提供的最低愉悦度。

Input

输入的第一行包含一个整数N,表示T 城中的景点个数。景点编号为 0...N − 1。接下来N − 1 行,每行三个整数u、v 和w,表示有一条u 到v,使 Ray 愉悦度增加w 的桥。桥的编号为1...N − 1。|w| <= 1000。输入的第N + 1 行包含一个整数M,表示Ray 的操作数目。接下来有M 行,每行描述了一个操作,操作有如下五种形式: C i w,表示Ray 对于经过第i 座桥的愉悦度变成了w。 N u v,表示Ray 对于经过景点u 到v 的路径上的每一座桥的愉悦度都变成原来的相反数。 SUM u v,表示询问从景点u 到v 所获得的总愉悦度。 MAX u v,表示询问从景点u 到v 的路径上的所有桥中某一座桥所提供的最大愉悦度。 MIN u v,表示询问从景点u 到v 的路径上的所有桥中某一座桥所提供的最小愉悦度。测试数据保证,任意时刻,Ray 对于经过每一座桥的愉悦度的绝对值小于等于1000。

Output

对于每一个询问(操作S、MAX 和MIN),输出答案。

Sample Input

3
0 1 1
1 2 2
8
SUM 0 2
MAX 0 2
N 0 1
SUM 0 2
MIN 0 2
C 1 3
SUM 0 2
MAX 0 2

Sample Output

3
2
1
-1
5
3

HINT

一共有10 个数据,对于第i (1 <= i <= 10) 个数据, N = M = i * 2000。

题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=2157

这道题给出的是边权,所以我们要把它转换成点权。

题目要求操作:

1.查询景区u,v之间所有桥愉悦值的总和

2.查询景区u,v之间桥愉悦值的最大值

3.查询景区u,v之间桥愉悦值的最小值

4.把景区u,v之间桥的愉悦值全部-1

5.把第i座桥的愉悦值修改为C

思路:因为城市任意两点之间只有一条路径,于是可以把这座城市看成是一颗树,用树链剖分可以进行上面需要的操作。

细节:

1.向下更新时,把左右孩子的lazy标记异或1,而不是直接赋1

2.区间值-1时,把维护的suml取反,maxl,minl交换后取反即可

3.所谓的桥,即是我们用邻接表存储的边,这里我们从下标2开始存储边,因为存储的是无向边,所以我们只需把桥的编号 i << 1, i << 1 | 1得到的即是邻接表edge的下标

(例如第一条桥肯定是edge[2],edge[3]),这样我们就能找到每条桥对应的点了(然后比较一下两条边的dep,这条桥的权值属于深度较大的点),这样我们就成功地把边权转换为了点权

4.景区u,v之间进行操作时,当两个点u,v跳到同一条重链时,深度较小的点的权值不应被考虑,因为操作的是u,v之间的边权,深度较小点的边权肯定不在u,v之间

Code:

#include <cmath>
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <ctype.h>
#include <map>
#include <vector>
#include <set>
#include <bitset>
#define lson rt << 1, l, mid
#define rson rt << 1 | 1, mid + 1, r
#define L(rt) rt << 1
#define R(rt) rt << 1 | 1
#define INF 0x7fffffff
#define eps 1e-9
#define pi acos(-1.0)
using namespace std;
typedef long long ll;
static const int MAX_N = 1e5 + 5;
static const int Mod = 10007;
struct Edge {
	int to, w, next;
}edge[MAX_N << 1];
int head[MAX_N];    //链式前向星
int a[MAX_N];
int siz[MAX_N], son[MAX_N], top[MAX_N], fa[MAX_N], id[MAX_N], dep[MAX_N], rk[MAX_N];
int cnt, tot;
void dfs1(int u, int f, int d) {     //第一次dfs得到重儿子
	siz[u] = 1;
	son[u] = 0;
	fa[u] = f;
	dep[u] = d;
	for (int i = head[u]; i; i = edge[i].next) {
		int v = edge[i].to;
		if (v == f) continue;    //不走重复路
		a[v] = edge[i].w;
		dfs1(v, u, d + 1);
		siz[u] += siz[v];
		if (siz[v] > siz[son[u]]) son[u] = v;
	}
}
void dfs2(int u, int t) {     //将重儿子连接成重链,轻儿子连接成轻链(得到区间)
	top[u] = t;
	id[u] = ++cnt;
	rk[cnt] = u;
	if (son[u]) dfs2(son[u], t);  //优先处理重链
	for (int i = head[u]; i; i = edge[i].next) {
		int v = edge[i].to;
		if (v != son[u] && v != fa[u]) dfs2(v, v);
	}
}
int getPoint(int u) { return dep[edge[u << 1].to] > dep[edge[u << 1 | 1].to] ? edge[u << 1].to : edge[u << 1 | 1].to; }
struct Node {
	int l, r;
	int minl, maxl, suml, tag;
}T[MAX_N << 2];
void prework() {
	memset(head, 0, sizeof(head));
	cnt = 0;
	tot = 1;
}
void addEdge(int u, int v, int w) {
	edge[++tot].to = v;
	edge[tot].next = head[u];
	edge[tot].w = w;
	head[u] = tot;
}
void pushUp(int rt) {
	T[rt].suml = T[L(rt)].suml + T[R(rt)].suml;
	T[rt].maxl = max(T[L(rt)].maxl, T[R(rt)].maxl);
	T[rt].minl = min(T[L(rt)].minl, T[R(rt)].minl);
}
void build(int rt, int l, int r) {
	T[rt].l = l;
	T[rt].r = r;
	T[rt].tag = 0;
	if (l == r) {
		T[rt].maxl = T[rt].minl = T[rt].suml = a[rk[l]];
		return;
	}
	int mid = l + r >> 1;
	build(lson);
	build(rson);
	pushUp(rt);
}
void pushNow(int rt) {
	swap(T[rt].maxl, T[rt].minl);
	T[rt].maxl = -T[rt].maxl;
	T[rt].minl = -T[rt].minl;
	T[rt].suml = -T[rt].suml;
	T[rt].tag ^= 1;
}
void pushDown(int rt) {
	if (T[rt].tag) {
		pushNow(L(rt));
		pushNow(R(rt));
		T[rt].tag = 0;
	}
}
void updatePoint(int rt, int pos, int c) {
	if (T[rt].l == T[rt].r) {
		T[rt].maxl = T[rt].minl = T[rt].suml = c;
		return;
	}
	pushDown(rt);
	int mid = T[rt].l + T[rt].r >> 1;
	if (pos <= mid) updatePoint(L(rt), pos, c);
	else updatePoint(R(rt), pos, c);
	pushUp(rt);
}
void updateInterval(int rt, int ql, int qr) {
	if (T[rt].l > qr || T[rt].r < ql) return;
	if (T[rt].l >= ql && T[rt].r <= qr) {
		pushNow(rt);
		return;
	}
	pushDown(rt);
	int mid = T[rt].l + T[rt].r >> 1;
	if (ql <= mid) updateInterval(L(rt), ql, qr);
	if (qr > mid) updateInterval(R(rt), ql, qr);
	pushUp(rt);
}
int queryMax(int rt, int ql, int qr) {
	if (T[rt].l > qr || T[rt].r < ql) return -INF;
	if (T[rt].l >= ql && T[rt].r <= qr) return T[rt].maxl;
	pushDown(rt);
	int ans = -INF;
	int mid = T[rt].l + T[rt].r >> 1;
	if (ql <= mid) ans = max(ans, queryMax(L(rt), ql, qr));
	if (qr > mid) ans = max(ans, queryMax(R(rt), ql, qr));
	return ans;
}
int querySum(int rt, int ql, int qr) {
	if (T[rt].l > qr || T[rt].r < ql) return 0;
	if (T[rt].l >= ql && T[rt].r <= qr) return T[rt].suml;
	pushDown(rt);
	int mid = T[rt].l + T[rt].r >> 1;
	int ans = 0;
	if (ql <= mid) ans += querySum(L(rt), ql, qr);
	if (qr > mid) ans +=  querySum(R(rt), ql, qr);
	return ans;
}
int queryMin(int rt, int ql, int qr) {
	if (T[rt].l > qr || T[rt].r < ql) return INF;
	if (T[rt].l >= ql && T[rt].r <= qr) return T[rt].minl;
	pushDown(rt);
	int ans = INF;
	int mid = T[rt].l + T[rt].r >> 1;
	if (ql <= mid) ans = min(ans, queryMin(L(rt), ql, qr));
	if (qr > mid) ans = min(ans, queryMin(R(rt), ql, qr));
	return ans;
}
void updatePathVal(int u, int v) {
	while (top[u] != top[v]) {
		if (dep[top[u]] < dep[top[v]]) swap(u, v);
		updateInterval(1, id[top[u]], id[u]);
		u = fa[top[u]];
	}
	if (dep[u] > dep[v]) swap(u, v);
	updateInterval(1, id[u] + 1, id[v]);
}
int queryPathMax(int u, int v) {
	int ans = -INF;
	while (top[u] != top[v]) {
		if (dep[top[u]] < dep[top[v]]) swap(u, v);
		ans = max(ans, queryMax(1, id[top[u]], id[u]));
		u = fa[top[u]];
	}
	if (dep[u] > dep[v]) swap(u, v);
	ans = max(ans, queryMax(1, id[u] + 1, id[v]));
	return ans;
}
int queryPathSum(int u, int v) {
	int ans = 0;
	while (top[u] != top[v]) {
		if (dep[top[u]] < dep[top[v]]) swap(u, v);
		ans += querySum(1, id[top[u]], id[u]);
		u = fa[top[u]];
	}
	if (dep[u] > dep[v]) swap(u, v);
	ans += querySum(1, id[u] + 1, id[v]);
	return ans;
}
int queryPathMin(int u, int v) {
	int ans = INF;
	while (top[u] != top[v]) {
		if (dep[top[u]] < dep[top[v]]) swap(u, v);
		ans = min(ans, queryMin(1, id[top[u]], id[u]));
		u = fa[top[u]];
	}
	if (dep[u] > dep[v]) swap(u, v);
	ans = min(ans, queryMin(1, id[u] + 1, id[v]));
	return ans;
}
void mainwork(){
	/*freopen("input.txt", "r", stdin);
	freopen("output.txt", "w", stdout);*/
	int n, q;
	scanf("%d", &n);
	for (int i = 1; i < n; ++i) {
		int u, v, w;
		scanf("%d%d%d", &u, &v, &w);
		++u, ++v;
		addEdge(u, v, w);
		addEdge(v, u, w);
	}
	dfs1(1, 1, 1);
	dfs2(1, 1);
	build(1, 1, n);
	scanf("%d", &q);
	while (q--) {
		char opt[5];
		int u, v, c;
		scanf("%s%d%d", opt, &u, &v);
		if (opt[0] == 'C') updatePoint(1, id[getPoint(u)], v);
		else if (opt[0] == 'N') updatePathVal(u + 1, v + 1);
		else if (opt[1] == 'U') printf("%d\n", queryPathSum(u + 1, v + 1));
		else if (opt[1] == 'I') printf("%d\n", queryPathMin(u + 1, v + 1));
		else  printf("%d\n", queryPathMax(u + 1, v + 1));
	}
}
int main() {
	prework();
	mainwork();
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值