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. RouterOS基础安装配置

    安装 光盘安装 载入光盘,按"A"全选按"I"进行安装,然后提示不否用旧的配置,按"N"全新安装,警告时按"Y"确定 安 ...

  2. LA 4327 Parade(单调队列优化dp)

    题目链接: 题目大意(摘自刘汝佳<<算法竞赛入门经典--训练指南>>):F城是由n+1条横向路和m+1条竖向路组成.你的任务是从最南边的路走到最北边的路,使得走过的路上的高兴值 ...

  3. java:集合输出之foreach输出三

    java:集合输出之foreach输出三 foreach输出: List<String> allList = new ArrayList<String>(); allList. ...

  4. python-语言播报

       利用系统自带模块: 在cmd中  python -m pip install pypiwin32   安装win32com模块 import win32com.client sp=win32co ...

  5. appium环境666

    一.安装JDK,配置JDK环境    appium下载地址: https://github.com/appium/appium-desktop/releases/ 百度搜索下载就行,这里分享一个下载链 ...

  6. 小程序-登录-token

    1.前端调用wx.login()获取code值 2.前端通过调用wx.getUserInfo获取iv.rawData.signature.encryptedData等加密数据,传递给后端 3.服务器通 ...

  7. [window] Pyhton轻便好用的spyder IDE如何去除E501 line too long提示

    spyder 使用pep8作为代码规范的标准,默认单行长度是89个字符以内. 作为一个完美控,在使用spyer有的进行coding时,每当看到以下这个小小的warning时,心情都不是很爽: 89个字 ...

  8. java mar --->JSONArray.fromObject

    <dependency> <groupId>net.sf.json-lib</groupId> <artifactId>json-lib</art ...

  9. Django REST framework入门 (转自中文文档)

    快速入门 我们将创建一个简单的允许管理员用户查看和编辑系统中的用户和组的API. 项目设置 创建一个名为 tutorial 的新django项目,然后启动一个名为 quickstart 的新app. ...

  10. Spring Cloud教程(十)自定义引导配置属性源

    可以通过在org.springframework.cloud.bootstrap.BootstrapConfiguration键下添加条目/META-INF/spring.factories来训练引导 ...