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++\) 的语言. 所以打完了 ...
随机推荐
- 2018ECNA Difference[时空复杂度]
目录 题干 代码和解释 题干 代码和解释 本题给出一个数列的第一个数A(1),要求找出m第一次出现(直接出现在数列中或是数列中某两项的差的绝对值)在这个数列的第几步中.数列递推公式:A(n+1)=A( ...
- Excel自动语音点名-视频教学
请看2019年9月5日发布的第一篇推文. 标题:Excel自动语音点名-视频教学. 如果是笔记本的话, 要连接音频线进行扩音. 效果非常好. 测试了下, 11个人, 用了27秒. 可以休息下喉咙啦.. ...
- 测试winform自动悬浮
using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using Sy ...
- vue的跳转方式(打开新页面)及传参
1. router-link跳转 // 直接写上跳转的地址 <router-link to="/detail/one"> <span class="sp ...
- IntelliJ IDEA-设置字体大小
setting 设置字体font大小,点击apply-ok
- Python知乎上推荐的项目
原文地址:https://www.zhihu.com/question/29372574/answer/88744491 作者:Wayne Shi链接:https://www.zhihu.com/qu ...
- Spring boot与Spring cloud之间的关系
Spring boot 是 Spring 的一套快速配置脚手架,可以基于spring boot 快速开发单个微服务,Spring Boot,看名字就知道是Spring的引导,就是用于启动Spring的 ...
- ES6----拓展运算符 三个点【...】
[...]拓展运算符是什么? es6中引入扩展运算符(...),它用于把一个数组转化为用逗号分隔的参数序列,它常用在不定参数个数时的函数调用,数组合并等情形.因为typeScript是es6的超集,所 ...
- Embed MP4 in HTML using flash-player(html5 video player)
https://stackoverflow.com/questions/1000851/embed-mp4-in-html-using-flash-player ******************* ...
- 泡泡一分钟:Real-Time Vehicle Detection from Short-Range Aerial Image with Compressed MobileNet
张宁 Real-Time Vehicle Detection from Short-Range Aerial Image with Compressed MobileNet链接:https://pan ...