SP375 QTREE - Query on a tree (树剖)
题目
解析
也就是个蓝题,因为比较长
树剖裸题(基本上),单点修改,链上查询。
顺便来说一下链上操作时如何将边上的操作转化为点上的操作:
可以看到这个题然我们对边进行操作,我们的树剖是对节点进行操作的,所以我们考虑把边权变为点权。

发现我们节点的点权是连向它的边的边权,所以我们要操作边权的话,我们操作的实际上是其连向点的点权,
假设我们要修改1-4之间的这两条边
我们修改的实际上就是这2,4两个点
我们节点的点权为其父节点连向它的边的边权,所以我们链上修操作的时候,不要操作深度较低的节点,因为它代表的边是它的父节点连向它的那一条,不是要操作的两点之间的边,就像上图我们不操作1号节点一样。
不用特意判断;两个位置的深浅,树剖中会判断,详见这里
再说一下这个题的修改,因为我们是要修改边权,我们的边权给了点,所以我们找一下这条边连的两个点,判断两个点的深度,较深的那个是我们要修改的点。
然后这是SPOJ上的题,我不知道为啥我写c++会挂,经king丨帝御威大佬的指点才用c过的,%%%
代码
#include <ctype.h>
#include <stdio.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#define lson rt << 1
#define rson rt << 1 | 1
#define N 10007
int t, n, m, num, cnt;
int head[N], a[N], w[N], son[N], size[N], f[N], top[N], dep[N], id[N], mx[N << 2];
class node {
public :
int nx, v, w;
} e[N << 2];
void add(int u, int v, int w) {
e[++num].nx = head[u], e[num].v = v, e[num].w = w, head[u] = num;
}
int max(int a, int b) { return a > b ? a : b; }
#define swap(A, B) \
{ \
int __T = A; \
A = B; \
B = __T; \
}
void dfs1(int u, int fa) {
size[u] = 1;
for (int i = head[u]; ~i; i = e[i].nx) {
int v = e[i].v;
if (v != fa) {
dep[v] = dep[u] + 1;
f[v] = u;
w[v] = e[i].w; //边权赋给点
dfs1(v, u);
size[u] += size[v];
if (size[v] > size[son[u]]) son[u] = v;
}
}
}
void dfs2(int u, int t) {
id[u] = ++cnt;
a[cnt] = w[u];
top[u] = t;
if (son[u]) dfs2(son[u], t);
for (int i = head[u]; ~i; i = e[i].nx) {
int v = e[i].v;
if (v != f[u] && v != son[u]) dfs2(v, v);
}
}
void pushup(int rt) {
mx[rt] = max(mx[lson], mx[rson]);
}
void build(int l, int r, int rt) {
if (l == r) {
mx[rt] = a[l];
return ;
}
int m = (l + r) >> 1;
build(l, m, lson);
build(m + 1, r, rson);
pushup(rt);
}
void update(int L, int c, int l, int r, int rt) {
if (l == r) {
mx[rt] = c;
return ;
}
int m = (l + r) >> 1;
if (L <= m) update(L, c, l, m, lson);
else update(L, c, m + 1, r, rson);
pushup(rt);
}
int query(int L, int R, int l, int r, int rt) {
if (L <= l && r <= R) return mx[rt];
int m = (l + r) >> 1, ans = -0x3f3f3f3f;
if (L <= m) ans = max(ans, query(L, R, l, m, lson));
if (R > m) ans = max(ans, query(L, R, m + 1, r, rson));
return ans;
}
int query_chain(int x, int y) {
int fx = top[x], fy = top[y], ans = -0x3f3f3f3f;
while (fx != fy) {
if (dep[fx] < dep[fy]) {
swap(x, y);
swap(fx, fy);
}
ans = max(ans, query(id[fx], id[x], 1, cnt, 1));
x = f[fx], fx = top[x];
}
if (id[x] > id[y]) swap(x, y);
ans = max(ans, query(id[x] + 1, id[y], 1, cnt, 1));
/*在这里注意是id[x]+1->id[y],不要算上深度较浅的点*/
return ans;
}
int main() {
scanf("%d", &t);
while (t -- ) {
num = cnt = 0;
memset(head, -1, sizeof(head));
memset(dep, 0, sizeof(dep));
memset(id, 0, sizeof(id));
memset(a, 0, sizeof(a));
memset(w, 0, sizeof(w));
memset(top, 0, sizeof(top));
memset(size, 0, sizeof(size));
memset(e, 0, sizeof(e));
memset(mx, 0, sizeof(mx));
memset(son, 0, sizeof(son));
memset(f, 0, sizeof(f));
scanf("%d", &n);
for (int i = 1, x, y, z; i < n; ++i) {
scanf("%d%d%d", &x, &y, &z);
add(x, y, z), add(y, x, z);
}
dfs1(1, 0), dfs2(1, 1);
build(1, n, 1);
char s[20];
int x, y;
while (1) {
scanf("%s", s);
if (s[0] == 'D') break;
else if (s[0] == 'C') {
scanf("%d%d", &x, &y);
x = dep[e[x << 1].v] > dep[e[(x << 1) - 1].v] ? e[x << 1].v : e[(x << 1) - 1].v;
/*因为是无向边,加了两次,两次的v都不是一个点*/
update(id[x], y, 1, n, 1);
} else {
scanf("%d%d", &x, &y);
printf("%d\n", query_chain(x, y));
}
}
}
return 0;
}
SP375 QTREE - Query on a tree (树剖)的更多相关文章
- SPOJ QTREE Query on a tree 树链剖分+线段树
题目链接:http://www.spoj.com/problems/QTREE/en/ QTREE - Query on a tree #tree You are given a tree (an a ...
- spoj QTREE - Query on a tree(树链剖分+线段树单点更新,区间查询)
传送门:Problem QTREE https://www.cnblogs.com/violet-acmer/p/9711441.html 题解: 树链剖分的模板题,看代码比看文字解析理解来的快~~~ ...
- SPOJ QTREE Query on a tree --树链剖分
题意:给一棵树,每次更新某条边或者查询u->v路径上的边权最大值. 解法:做过上一题,这题就没太大问题了,以终点的标号作为边的标号,因为dfs只能给点分配位置,而一棵树每条树边的终点只有一个. ...
- SP375 QTREE - Query on a tree
题意大意 给定\(n\)个点的树,边按输入顺序编号为\(1,2,...n-1\),要求作以下操作: CHANGE \(i\) \(t_i\) 将第\(i\)条边权值改为\(t_i\),QUERY \( ...
- spoj 375 QTREE - Query on a tree 树链剖分
题目链接 给一棵树, 每条边有权值, 两种操作, 一种是将一条边的权值改变, 一种是询问u到v路径上最大的边的权值. 树链剖分模板. #include <iostream> #includ ...
- SPOJ QTREE Query on a tree ——树链剖分 线段树
[题目分析] 垃圾vjudge又挂了. 树链剖分裸题. 垃圾spoj,交了好几次,基本没改动却过了. [代码](自带常数,是别人的2倍左右) #include <cstdio> #incl ...
- QTREE - Query on a tree
QTREE - Query on a tree 题目链接:http://www.spoj.com/problems/QTREE/ 参考博客:http://blog.sina.com.cn/s/blog ...
- SPOJ 375 树链剖分 QTREE - Query on a tree
人生第一道树链剖分的题目,其实树链剖分并不是特别难. 思想就是把树剖成一些轻链和重链,轻链比较少可以直接修改,重链比较长,用线段树去维护. 貌似大家都是从这篇博客上学的. #include <c ...
- 题解 SP375 【QTREE - Query on a tree】
\[ \texttt{Preface} \] 这题在 \(\text{Luogu}\) 上竟然不能交 \(C++\) ,会一直 \(Waiting\) ,只能交非 \(C++\) 的语言. 所以打完了 ...
随机推荐
- ping某域名的整个流程
实验环境:主机A,B(可不再同一网段),主机B有域名假设为www.baidu.com首先:1. 本地主机A在命令行下执行"ipconfig/flushdns"命令来清空本地DNS高 ...
- Arbitrary Style Transfer in Real-time with Adaptive Instance Normalization
Arbitrary Style Transfer in Real-time with Adaptive Instance Normalization 2019-10-10 10:50:19 Paper ...
- essay sundry
感觉很多单词, 即使是所谓的抽象名词都有复数形式,是习惯用法,比如, details, comments, ads等 ad: 广告, advertise的缩写? advertise. advertis ...
- vue中axios使用二:axios以post,get,jsonp的方式请求后台数据
本文为博主原创,转载请注明出处 axios在上一篇中讲过:vue中axios使用一:axios做拦截器,axios是请求后台资源的模块,用来请求后台资源. axios本身是支持get,post请求后台 ...
- 在 Windows 服务中托管 ASP.NET Core
众所周知,ASP.NET Core采用了和传统ASP.NET不同的托管和HTTP处理方式,即把服务器和托管环境完全解耦.ASP.NET Core内置了两个HTTP服务器实现,一个是基于libuv实现的 ...
- Springboot 条件注解
@Conditional 根据满足某一个特定条件创建一个特定的 Bean.就是根据特定条件来控制 Bean 的创建行为,这样我们可以利用这个特性进行一些自动的配置 Springboot 中大量用到了条 ...
- anaconda 安装指定源的包
当前知道的有两种方式可以查找: 1.conda search 命令:conda search pkg_name 安装的时候直接:conda install cudatoolkit=版本后 conda ...
- 【转载】 tf.cond() ----------------------(tensorflow 条件判断语句 if.......else....... )
原文地址: https://cloud.tencent.com/developer/article/1486441 ------------------------------------------ ...
- Android Studio运行Hello World程序
老的神舟本本装上了深度LINUX了...应该是基于ubuntu的,安装软件用的apt-get而不是yum 想重装学下android原生开发,官网下载了android studio, 发现不用FQ也能下 ...
- asp.net 的log4net的helper类
using log4net; using System; using System.Diagnostics; namespace MxWeiXinPF.Common.log { public stat ...