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++\) 的语言. 所以打完了 ...
随机推荐
- @Autowired和@Resource的区别和联系
背景: 今天下班路上看到一个大货车,于是想到了装配,然后脑海里跳出了一个注解@Autowired(自动装配),于是又想到最近工作项目用的都是@Resource注解来进行装配.于是本着学什么东西都要一钻 ...
- Delaunay和Voronoi
什么是Delaunay三角剖分? 图1:Delaunay三角剖分偏爱小角度 给定平面中的一组点,三角剖分指的是将平面细分为三角形,这些点为顶点.在图1中,我们在左侧图像上看到了一组地标,在中间图像上看 ...
- 华为云ARM64服务器试用
公司同事弄了个华为云的ARM64服务器,让我帮忙部署我们的服务,所以先试用了一下. 总体感觉还行,使用的CentOS系统,yum也能用,epel源也可以用.但是SCL软件集用不了. uname -a ...
- Nginx之Rewrite规则
IF语句: http://tengine.taobao.org/nginx_docs/cn/docs/http/ngx_http_rewrite_module.html#if 首先申明nginx只有i ...
- EasyDSS高性能RTMP、HLS(m3u8)、HTTP-FLV、RTSP流媒体服务器解决方案之CDN内容分发网络
背景分析 EasyDSS流媒体解决方案提供一站式的转码.点播.直播.录像.检索.时移回放服务,极大地简化了开发和集成的工作,并且EasyDSS支持多种特性,完全能够满足企业视频信息化建设方面的需求.其 ...
- photoshop7.0 排版一寸照片、2寸照片
说明:必须先照一张一寸电子照片,否则是无法做成 1.本例同样采用photoshop CS5制作,其它版本通用,这里采用上一教程“PS照片处理教程-制作一寸照片并排版”的处理效果图进行排版,首先在PS中 ...
- SecureCRT-登录unix/linux服务器主机的软件
百度百科说辞: SecureCRT是一款支持SSH(SSH1和SSH2)的终端仿真程序,简单地说是Windows下登录UNIX或Linux服务器主机的软件. SecureCRT支持SSH,同时支持Te ...
- linux内存管理swap分区
一.什么是linux的内存机制? 我们知道,直接从物理内存读写数据要比从硬盘读写数据要快的多,因此,我们希望所有数据的读取和写入都在内存完成,而内存是有限的,这样就引出了物理内存与虚拟内存的概念. 物 ...
- spring boot实现切割分片上传
文件上传是web开发中经常会遇到的 springboot的默认配置为10MB,大于10M的是传不上服务器的,需要修改默认配置 但是如果修改支持大文件又会增加服务器的负担. 当文件大于一定程度时,不仅服 ...
- ES6学习小结
ES6(ES2015)--IE10+.Chrome.FireFox.移动端.NodeJS 编译.转换 1.在线转换 2.提前编译 babel = browser.js ES6: 1.变量 var 重复 ...