一 题目

  QTREE

二 分析

  第一道树链剖分的题,写的好艰难啊。

  题意还是比较好理解的,就是在树上操作。

  对于修改,题中要求的是单点修改,就算是直接树上操作也是非常简单的。

  对于查询,查询的时候,是查询树上一个结点到另一个结点的这条上的最大值。这里就需要用树链剖分了。

  树链剖分,其实就是把树型转换为线型的一种思想。通过剖分一棵树,可以得到很多的链,这些链保证了,树上的相邻节点在链中也一定是相邻的,这样,我们在操作的时候,就可以看做是对链进行更细致的操作了。对链操作时,还要将转换成的线性结构用线段树来维护,单点修改的同时保证快速求出最大值。

  代码可以分为两部分,第一部分是树链剖分部分,第二部分就是线段树了(于普通线段树没有什么区别)。

三 AC代码

  1 #include <bits/stdc++.h>
2
3 using namespace std;
4
5 const int MAXN = 1e5 + 15;
6 int N;
7 int e[MAXN][3];
8 //临接链表建图
9 //双向的!
10 struct Edge
11 {
12 int to, next;
13 }edge[MAXN*2];
14 int head[MAXN], tot;
15
16 int fa[MAXN]; //父节点
17 int size[MAXN]; //以节点为根的子数大小
18 int deep[MAXN]; //深度
19 int son[MAXN]; //重儿子
20 int top[MAXN]; //重链的最高点
21 int p[MAXN]; //结点在整棵树中的编号
22 int fp[MAXN]; //p的反向
23 int pos;
24
25 void init()
26 {
27 tot = 0, pos = 0;
28 memset(head, -1, sizeof(head));
29 memset(son, -1, sizeof(son));
30 }
31
32 void addedge(int u, int v)
33 {
34 edge[tot].to = v;
35 edge[tot].next = head[u];
36 head[u] = tot++;
37 }
38
39 void dfs1(int u, int pre, int d)
40 {
41 deep[u] = d;
42 fa[u] = pre;
43 size[u] = 1;
44 for(int i = head[u]; i != -1; i = edge[i].next)
45 {
46 int v = edge[i].to;
47 //因为建的是双向图
48 if(v != pre)
49 {
50 dfs1(v, u, d+1);
51 size[u] += size[v];
52 if(son[u] == -1 || size[v] > size[son[u]])
53 son[u] = v;
54 }
55 }
56 }
57
58 void dfs2(int u, int sp)
59 {
60 top[u] = sp;
61
62 if(son[u] != -1)
63 {
64 p[u] = pos++;
65 //血的教训把fp写成了fa!!!
66 fp[p[u]] = u;
67 dfs2(son[u], sp);
68 }
69 else
70 {
71 p[u] = pos++;
72 fp[p[u]] = u;
73 return;
74 }
75
76 for(int i = head[u]; i != -1; i = edge[i].next)
77 {
78 int v = edge[i].to;
79 if(v != son[u] && v != fa[u])
80 dfs2(v, v);
81 }
82 }
83
84 struct Node
85 {
86 int l, r, Max;
87 }segTree[MAXN*3];
88
89 void build(int rt, int l, int r)
90 {
91 segTree[rt].l = l;
92 segTree[rt].r = r;
93 segTree[rt].Max = 0;
94 if(l == r) return;
95 int mid = (l + r) >> 1;
96 build(rt<<1, l, mid);
97 build(rt<<1|1, mid + 1, r);
98 }
99
100 void push_up(int rt)
101 {
102 segTree[rt].Max = max(segTree[rt<<1].Max, segTree[rt<<1|1].Max);
103 }
104
105 void update(int rt, int k, int val)
106 {
107 if(segTree[rt].l == segTree[rt].r)
108 {
109 segTree[rt].Max = val;
110 return;
111 }
112 int mid = (segTree[rt].l + segTree[rt].r) >> 1;
113 if(k <= mid)
114 update(rt<<1, k, val);
115 else
116 update(rt<<1|1, k, val);
117 push_up(rt);
118 }
119
120 int query(int rt, int l, int r)
121 {
122 if(segTree[rt].l == l && segTree[rt].r == r)
123 {
124 return segTree[rt].Max;
125 }
126 int mid = (segTree[rt].l + segTree[rt].r) >> 1;
127 if(r <= mid)
128 return query(rt<<1, l, r);
129 else if(l > mid)
130 return query(rt<<1|1, l, r);
131 else
132 {
133 return max(query(rt<<1, l, mid), query(rt<<1|1, mid + 1, r));
134 }
135 }
136
137 int find(int u, int v)
138 {
139 int f1 = top[u], f2 = top[v];
140 int tmp = 0;
141 //保证u的节点编号比v小
142 //且u,v跳到一条链上去
143 while(f1 != f2)
144 {
145 if(deep[f1] < deep[f2])
146 {
147 swap(f1, f2);
148 swap(u, v);
149 }
150 //跳深度深(链更低)的链顶点
151 tmp = max(tmp, query(1, p[f1], p[u]));
152 u = fa[f1];
153 f1 = top[u];
154 }
155 if(u == v) return tmp;
156 if(deep[u] > deep[v]) swap(u, v);
157 return max(tmp, query(1, p[son[u]], p[v]));
158
159 }
160
161
162 int main()
163 {
164 //freopen("input.txt", "r", stdin);
165 int T;
166 scanf("%d", &T);
167 while(T--)
168 {
169
170 init();
171 char op[10];
172 int u, v;
173 scanf("%d", &N);
174 for(int i = 0; i < N-1; i++)
175 {
176 scanf("%d %d %d", &e[i][0], &e[i][1], &e[i][2]);
177 addedge(e[i][0], e[i][1]);
178 addedge(e[i][1], e[i][0]);
179 }
180 dfs1(1, 0, 0);
181 dfs2(1, 1);
182 build(1, 0, pos - 1);
183
184 for(int i = 0; i < N-1; i++)
185 {
186 if(deep[e[i][0]] < deep[e[i][1]])
187 swap(e[i][0], e[i][1]);
188 update(1, p[e[i][0]], e[i][2]);
189 }
190 while(scanf("%s", op) == 1)
191 {
192 if(op[0] == 'D')
193 break;
194 scanf("%d %d", &u, &v);
195 if(op[0] == 'C')
196 update(1, p[e[u-1][0]], v);
197 else
198 printf("%d\n", find(u, v));
199 }
200 }
201 return 0;
202 }

SPOJ QTree【树链剖分】的更多相关文章

  1. SPOJ QTREE 树链剖分

    树链剖分的第一题,易懂,注意这里是边. #include<queue> #include<stack> #include<cmath> #include<cs ...

  2. Spoj Query on a tree SPOJ - QTREE(树链剖分+线段树)

    You are given a tree (an acyclic undirected connected graph) with N nodes, and edges numbered 1, 2, ...

  3. 【学术篇】SPOJ QTREE 树链剖分

    发现链剖这东西好久不写想一遍写对是有难度的.. 果然是熟能生巧吧.. WC的dalao们都回来了 然后就用WC的毒瘤题荼毒了我们一波, 本来想打个T1 44分暴力 然后好像是特判写挂了还是怎么的就只能 ...

  4. QTREE 树链剖分---模板 spoj QTREE

    <树链剖分及其应用> 一文讲得非常清楚,我一早上就把他学会了并且A了这题的入门题. spoj QTREE 题目: 给出一棵树,有两种操作: 1.修改一条边的边权. 2.询问节点a到b的最大 ...

  5. SPOJ 375 树链剖分 QTREE - Query on a tree

    人生第一道树链剖分的题目,其实树链剖分并不是特别难. 思想就是把树剖成一些轻链和重链,轻链比较少可以直接修改,重链比较长,用线段树去维护. 貌似大家都是从这篇博客上学的. #include <c ...

  6. SPOJ 375 树链剖分

    SPOJ太慢了,SPOJ太慢了, 题意:给定n(n<=10000)个节点的树,每条边有边权,有两种操作:1.修改某条变的边权:2.查询u,v之间路径上的最大边权. 分析:树链剖分入门题,看这里: ...

  7. SPOJ 375 (树链剖分 - 边权剖分 - 修改单边权)

    题目链接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=28982#problem/I 给你一棵有边权的树,有两个操作:一个操作是输出l到 ...

  8. SPOJ 375 (树链剖分+线段树)

    题意:一棵包含N 个结点的树,每条边都有一个权值,要求模拟两种操作:(1)改变某条边的权值,(2)询问U,V 之间的路径中权值最大的边. 思路:最近比赛总是看到有树链剖分的题目,就看了论文,做了这题, ...

  9. SPOJ375.QTREE树链剖分

    题意:一个树,a b c 代表a--b边的权值为c.CHANGE x y  把输入的第x条边的权值改为y,QUERY x y 查询x--y路径上边的权值的最大值. 第一次写树链剖分,其实树链剖分只能说 ...

  10. spoj 375 树链剖分 模板

    QTREE - Query on a tree #tree You are given a tree (an acyclic undirected connected graph) with N no ...

随机推荐

  1. 创建AVL树,插入,删除,输出Kth Min

    https://github.com/TouwaErioH/subjects/tree/master/C%2B%2B/PA2 没有考虑重复键,可以在结构体内加一个int times. 没有考虑删除不存 ...

  2. OpenCV3.2+Python3.5+Ubuntu16.04+缺少boostdesc和vgg_generated

    问题: OpenCV3.2在cmake通过https无法获取boostdesc和vgg_generated2类文件 可尝试的解决方法: 参考, 依其方法至这里做调整, 最后注释xfeatures2d/ ...

  3. Apple Watch Series 6 屏幕误触放大后无法还原问题和解决方案

    Apple Watch Series 6 屏幕误触放大后无法还原问题和解决方案 shit Apple,只能放大,不能缩小! 解决方案 关闭缩放功能 https://support.apple.com/ ...

  4. 使用 js 实现十大排序算法: 计数排序

    使用 js 实现十大排序算法: 计数排序 计数排序 refs xgqfrms 2012-2020 www.cnblogs.com 发布文章使用:只允许注册用户才可以访问!

  5. JavaScript & Atomics

    JavaScript & Atomics Atomics 对象提供了一组静态方法对 SharedArrayBuffer 和 ArrayBuffer 对象进行原子操作. Atomics.add ...

  6. 算法的时间复杂度 & 性能对比

    算法的时间复杂度 & 性能对比 累加算法性能对比 // js 累加算法性能对比测试 const n = 10**6; (() => { console.time(`for`); let ...

  7. NGK DeFi项目即将上线,打造去中心化闭环金融生态!

    据最新官方消息称:NGK已于近日宣布将进军DeFi领域,NGK此次的DeFi的项目将会是一个去中心的交易平台,其最大的功能是进行数字货币的交换.在用户选择了需要支付的数字货币和想购买的数字货币后,系统 ...

  8. 按键显示器(判断键盘监听器获得的值为普通Key还中modifiers)

    1 import sys 2 from PyQt5 import QtWidgets,QtCore 3 from PyQt5.QtCore import Qt 4 from PyQt5.uic.pro ...

  9. JDK源码阅读-Reference

    本文转载自JDK源码阅读-Reference 导语 Java最初只有普通的强引用,只有对象存在引用,则对象就不会被回收,即使内存不足,也是如此,JVM会爆出OOME,也不会去回收存在引用的对象. 如果 ...

  10. 微信小程序(八)-项目实例(原生框架 MINA转云开发)==03-云开发-数据库

    云数据库 云数据库开发文档:https://developers.weixin.qq.com/miniprogram/dev/wxcloud/guide/database.html 1.新建云数据库( ...