https://www.luogu.org/problem/P4114

维护边权的话,用深度大的点表示这条边(可以遍历一边边询问两端深度,这样不需要修改dfs1,也可以在dfs1的时候向下走的同时把边权拷贝进深度大的点。),然后在链上问的时候,最后一次问的左端点要+1(小心左右端点原本重合)。

要注意每个点x实际上在线段树上的位置是tid[x],不要改错了。线段树build的时候初始化的不是a[x]而是a[rnk[x]],也就是x号线段树位置对应的dfn序,也就是节点本身(rnk和tid互为逆运算)。

#include<bits/stdc++.h>
#define lc (o<<1)
#define rc (o<<1|1)
typedef long long ll;
using namespace std; const ll INF = 1e18; const int MAXN = 100000 + 5;
int dep[MAXN], siz[MAXN], son[MAXN], fa[MAXN], top[MAXN], tid[MAXN], rnk[MAXN], cnt; int n, m; int head[MAXN], etop;
struct Edge {
int v, w, next;
} e[MAXN * 2]; inline void init(int n) {
etop = 0;
memset(head, -1, sizeof(head[0]) * (n + 1));
} inline void addedge(int u, int v, int w) {
e[++etop].v = v;
e[etop].w = w;
e[etop].next = head[u];
head[u] = etop;
e[++etop].v = u;
e[etop].w = w;
e[etop].next = head[v];
head[v] = etop;
} int a[MAXN]; struct SegmentTree {
int ma[MAXN * 4]; void build(int o, int l, int r) {
if(l == r) {
ma[o] = a[rnk[l]];
} else {
int m = (l + r) >> 1;
build(lc, l, m);
build(rc, m + 1, r);
pushup(o);
}
} void pushup(int o) {
ma[o] = max(ma[lc], ma[rc]);
} void update(int o, int l, int r, int x, int v) {
if(l == r) {
ma[o] = v;
} else {
int m = (l + r) >> 1;
if(x <= m)
update(lc, l, m, x, v);
if(x >= m + 1)
update(rc, m + 1, r, x, v);
pushup(o);
}
} ll querymax(int o, int l, int r, int ql, int qr) {
if(ql <= l && r <= qr) {
return ma[o];
} else {
int m = (l + r) >> 1;
ll res = -INF;
if(ql <= m)
res = max(res, querymax(lc, l, m, ql, qr));
if(qr >= m + 1)
res = max(res, querymax(rc, m + 1, r, ql, qr));
return res;
}
}
} st; void init1() {
dep[1] = 1;
} void dfs1(int u, int t) {
siz[u] = 1, son[u] = -1, fa[u] = t;
for(int i = head[u]; i != -1; i = e[i].next) {
int v = e[i].v;
if(v == t)
continue;
dep[v] = dep[u] + 1;
a[v]=e[i].w;
dfs1(v, u);
siz[u] += siz[v];
if(son[u] == -1 || siz[v] > siz[son[u]])
son[u] = v;
}
} void init2() {
cnt = 0;
} void dfs2(int u, int t) {
top[u] = t;
tid[u] = ++cnt;
rnk[cnt] = u;
if(son[u] == -1)
return;
dfs2(son[u], t);
for(int i = head[u]; i != -1; i = e[i].next) {
int v = e[i].v;
if(v == fa[u] || v == son[u])
continue;
dfs2(v, v);
}
} ll querymax1(int u, int v) {
if(u == v)
return 0;
ll ret = -INF;
for(int tu = top[u], tv = top[v]; tu != tv; u = fa[tu], tu = top[u]) {
if(dep[tu] < dep[tv])
swap(u, v), swap(tu, tv);
ret = max(ret, st.querymax(1, 1, n, tid[tu], tid[u]));
}
if(tid[u] == tid[v])
return ret;
if(dep[u] > dep[v])
swap(u, v);
ret = max(ret, st.querymax(1, 1, n, tid[u] + 1, tid[v]));
return ret;
} void change() {
int i, val;
scanf("%d%d", &i, &val);
int u = e[2*i-1].v, v = e[2*i].v;
int x = u;
if(dep[v] > dep[u])
x = v;
st.update(1, 1, n, tid[x], val);
} void query() {
int u, v;
scanf("%d%d", &u, &v);
ll res = querymax1(u, v);
printf("%lld\n", res);
} int main() {
#ifdef Yinku
freopen("Yinku.in", "r", stdin);
#endif // Yinku
scanf("%d", &n);
init(n);
for(int i = 1, u, v, w; i <= n - 1; ++i) {
scanf("%d%d%d", &u, &v, &w);
addedge(u, v, w);
}
init1(),dfs1(1, -1);
init2(),dfs2(1, 1);
st.build(1, 1, n);
char op[20];
while(~scanf("%s", op)) {
switch(op[0]) {
case 'C':
change();
break;
case 'Q':
query();
break;
case 'D':
return 0;
}
}
return 0;
}

洛谷 - P4114 - Qtree1 - 重链剖分的更多相关文章

  1. 洛谷 P4114 Qtree1 树链剖分

    目录 题面 题目链接 题目描述 输入输出格式 输入格式: 输出格式: 输入输出样例 输入样例: 输出样例: 说明 说明 思路 Change Query AC代码 总结 题面 题目链接 P4114 Qt ...

  2. 洛谷P4114 Qtree1(树链剖分+线段树)

    传送门 LCT秒天秒地用什么树剖 这题可以算是树剖的比较裸的题目了 把每一条边的权值下放到他两边的点中深度较深的那个 然后直接用树剖+线段树带进去乱搞就可以了 //minamoto #include& ...

  3. 洛谷P4114 Qtree1

    题目描述 给定一棵\(n\)个节点的树,有两个操作: \(CHANGE\) \(i\) \(t_i\) 把第\(i\)条边的边权变成\(t_i\) \(QUERY\) \(a\) \(b\) 输出从\ ...

  4. 洛谷 P4114 Qtree1

    Qtree系列都跟树有着莫大的联系,这道题当然也不例外 我是题面 读完题,我们大概就知道了,这道题非常简单,可以说是模板题.树剖+线段树轻松解决 直接看代码吧 #include<algorith ...

  5. 树链剖分【洛谷P4114】 Qtree1

    P4114 Qtree1 题目描述 给定一棵n个节点的树,有两个操作: CHANGE i ti 把第i条边的边权变成ti QUERY a b 输出从a到b的路径中最大的边权,当a=b的时候,输出0 码 ...

  6. 【算法学习】【洛谷】树链剖分 & P3384 【模板】树链剖分 P2146 软件包管理器

    刚学的好玩算法,AC2题,非常开心. 其实很早就有教过,以前以为很难就没有学,现在发现其实很简单也很有用. 更重要的是我很好调试,两题都是几乎一遍过的. 介绍树链剖分前,先确保已经学会以下基本技巧: ...

  7. 洛谷P3384 树链剖分

    如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z 操作2: 格式: 2 x ...

  8. 洛谷.4114.Qtree1(树链剖分)

    题目链接 模板题都错了这么多次.. //边权赋到点上 树剖模板 //注意LCA.链的顶端不能统计到答案! #include <cstdio> #include <cctype> ...

  9. 【树链剖分】洛谷P3379 树链剖分求LCA

    题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每 ...

随机推荐

  1. python如何调用c编译好可执行程序

    python如何调用c编译好可执行程序       以下总结出几种在Python 中调用 C/C++ 代码的方法 ------------------------------------------- ...

  2. MongoDB的安装以及启动

    1.首先什么是MongoDB? MongoDB是一个基于分布式文件存储的数据库,是由c++语言编写的.为web应用提供可扩展的高性能数据的存储方案.是一个介于关系型数据库和非关系型数据库 的中间产品, ...

  3. 旧题再做【bzoj2287】【[pojchallenge]消失之物】分治背包

    (上不了p站我要死了) 今天听了 doggu神 讲了这道题的另一种做法,真是脑洞大开.眼界大开.虽然复杂度比黄学长的要大一点,但不总结一下简直对不起这神思路. 方法1:黄学长的做法(点这里) Desc ...

  4. Kohana Minion cli 学习

    1.E:\html\tproject\framebota\platform\bootstrap.php Kohana::modules(array( 'auth' => MODPATH.'aut ...

  5. 原生js实现简单的放大镜效果

    前言:相信很多同学在浏览购物网站的时候都会用到过放大镜的功能,这个功能在日常的网站也会经常用到.接下来我们开始实现一下它吧: (1)首先了解一下放大镜效果的html架构:如下图,它由两部分组成. ht ...

  6. VS2015中添加QT5.9.0插件

    https://blog.csdn.net/hhhuang1991/article/details/79768595 VS2015里使用QTDIR路径查找QT开发包目录 路径配置操作系统环境变量里添加 ...

  7. VxWorks BSP开发入门

    VxWorks将所有硬件平台相关的代码封装在BSP(Board Support Package)库中,从而为应用层代码提供了独立于硬件平台和体系接口的特性. BSP库中封装了一组统一的API,包括硬件 ...

  8. 模拟赛DAY1 T2腐草为萤

    2.腐草为萤(dzy.cpp/c) [题目背景] 纤弱的淤泥中妖冶颓废在季夏第三月最幼嫩的新叶连凋零都不屑何必生离死别——银临<腐草为萤> [问题描述] 扶苏给了你一棵树,这棵树上长满了幼 ...

  9. AtomicInteger 源码分析

    AtomicInteger AtomicInteger 能解决什么问题?什么时候使用 AtomicInteger? 支持原子更新的 int 值. 如何使用 AtomicInteger? 1)需要被多线 ...

  10. 错误 error: The following untracked working tree files would be overwritten by merge:README.md

    问题类型 相信很多小伙伴在创建新的git仓库后,会选上添加README.md文件,开始我也没太在意,应该也没有什么问题. 但是当我通过git添加远程仓库,给这个仓库上传代码时,出现了如下问题:erro ...