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++\) 的语言. 所以打完了 ...
随机推荐
- Spring项目中Properties不能加载多个的问题
A模块和B模块都分别拥有自己的Spring XML配置,并分别拥有自己的配置文件: A模块 A模块的Spring配置文件如下: <?xml version="1.0" enc ...
- Fiddler添加过滤条件
- linux下使用clamav排查病毒
clamav wget http://www.clamav.net/downloads/production/clamav-0.102.0.tar.gz ### Installyum -y insta ...
- Python示例项目学习
原文地址:http://www.360doc.com/showweb/0/0/874025604.aspx 「 Python3 实现火车票查询工具 」 相信很多人学Python都是冲着它强大的爬虫 ...
- java8在Stream的forEach操作时获取index
import java.util.Objects; import java.util.function.BiConsumer; /** * * @author yangzhilong * @dat ...
- NVM 安装注意
windows 系统下尽量使用安装版本,选择安装路径时,路径中不能带有空格,否则无法使用 nvm use xx.xx.xx
- PAT-2019年冬季考试-甲级 7-1 Good in C (20分)
7-1 Good in C (20分) When your interviewer asks you to write "Hello World" using C, can y ...
- Collections--ChainMap
一个 ChainMap 类是为了将多个映射快速的链接到一起,这样它们就可以作为一个单元处理.它通常比创建一个新字典和多次调用 update() 要快很多. class collections.Chai ...
- Putty——支持Telnet,ssh连接的连接软件
简介 PuTTY 的官方网站:http://www.chiark.greenend.org.uk/~sgtatham/putty/,截止到 2007年6月,发布的最高稳定版本是 0.6.PuTTY 是 ...
- PAt 1099
1099 Build A Binary Search Tree (30 分) A Binary Search Tree (BST) is recursively defined as a bina ...