SPOJ 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【树链剖分】的更多相关文章
- SPOJ QTREE 树链剖分
树链剖分的第一题,易懂,注意这里是边. #include<queue> #include<stack> #include<cmath> #include<cs ...
- 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, ...
- 【学术篇】SPOJ QTREE 树链剖分
发现链剖这东西好久不写想一遍写对是有难度的.. 果然是熟能生巧吧.. WC的dalao们都回来了 然后就用WC的毒瘤题荼毒了我们一波, 本来想打个T1 44分暴力 然后好像是特判写挂了还是怎么的就只能 ...
- QTREE 树链剖分---模板 spoj QTREE
<树链剖分及其应用> 一文讲得非常清楚,我一早上就把他学会了并且A了这题的入门题. spoj QTREE 题目: 给出一棵树,有两种操作: 1.修改一条边的边权. 2.询问节点a到b的最大 ...
- SPOJ 375 树链剖分 QTREE - Query on a tree
人生第一道树链剖分的题目,其实树链剖分并不是特别难. 思想就是把树剖成一些轻链和重链,轻链比较少可以直接修改,重链比较长,用线段树去维护. 貌似大家都是从这篇博客上学的. #include <c ...
- SPOJ 375 树链剖分
SPOJ太慢了,SPOJ太慢了, 题意:给定n(n<=10000)个节点的树,每条边有边权,有两种操作:1.修改某条变的边权:2.查询u,v之间路径上的最大边权. 分析:树链剖分入门题,看这里: ...
- SPOJ 375 (树链剖分 - 边权剖分 - 修改单边权)
题目链接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=28982#problem/I 给你一棵有边权的树,有两个操作:一个操作是输出l到 ...
- SPOJ 375 (树链剖分+线段树)
题意:一棵包含N 个结点的树,每条边都有一个权值,要求模拟两种操作:(1)改变某条边的权值,(2)询问U,V 之间的路径中权值最大的边. 思路:最近比赛总是看到有树链剖分的题目,就看了论文,做了这题, ...
- SPOJ375.QTREE树链剖分
题意:一个树,a b c 代表a--b边的权值为c.CHANGE x y 把输入的第x条边的权值改为y,QUERY x y 查询x--y路径上边的权值的最大值. 第一次写树链剖分,其实树链剖分只能说 ...
- spoj 375 树链剖分 模板
QTREE - Query on a tree #tree You are given a tree (an acyclic undirected connected graph) with N no ...
随机推荐
- sql-libs(2) 数字型
经测试,发现是数字型的注入,直接 and 1=1 返回正常,and1=2返回错误,感觉比第一关更加简单一点啊,,透~ 经测试order by 为 3 . 1. union 注入 http://192. ...
- Dva & Umi
Dva & Umi Dva.js & Umi.js React & Redux https://dvajs.com/ React and redux based, lightw ...
- 【目标检测】用Fast R-CNN训练自己的数据集超详细全过程
目录: 一.环境准备 二.训练步骤 三.测试过程 四.计算mAP 寒假在家下载了Fast R-CNN的源码进行学习,于是使用自己的数据集对这个算法进行实验,下面介绍训练的全过程. 一.环境准备 我这里 ...
- 云原生系列6 基于springcloud架构风格的本地debug实现
debug是程序员在日常开发中最常使用的操作, 那么,你是如何快速在微服务架构风格下快速debug后端服务呢? 开发现状 开发的理想状态 本地调测的使用步骤 登录智能网关 如果集成开发环境是在本地局域 ...
- Egg.js 是什么?
Egg.js 是什么? 阿里巴巴出 Egg.js 为企业级框架和应用而生,我们希望由 Egg.js 孕育出更多上层框架,帮助开发团队和开发人员降低开发和维护成本. 注:Egg.js 缩写为 Egg 设 ...
- django学习-3.如何编写一个html页面并展示到浏览器,及相关导入错误的解决方案
1.前言 在django中,视图的概念是:具有相同功能和模板的网页,都可以称为视图.通俗一点来说,就是你平常打开任一浏览器,输入一个地址A后看到浏览器窗口展示出来地址A所对应的页面内容B,页面内容B就 ...
- C/C++子函数参数传递,堆栈帧、堆栈参数详解
本文转载自C/C++子函数参数传递,堆栈帧.堆栈参数详解 导语 因为参数传递和汇编语言有很大联系,之后会出现较多x86汇编代码. 该文会先讲一下x86的堆栈参数传递过程,然后再分析C/C++子函数是怎 ...
- Nginx之Location匹配规则
概述 经过多年发展,nginx凭借其优异的性能征服了互联网界,成为了各个互联网公司架构设计中不可获取的要素.Nginx是一门大学问,但是对于Web开发者来说,最重要的是需要能捋的清楚Nginx的请求路 ...
- js合并字符串的3种方法和效率
/* abc abc abc*/function concat(s,n){ let a = new Array(n); a.fill(s); let str = a.join(''); a = nul ...
- node初体验(二)
1.静态资源访问,需要设置路由和响应标头 2.url模块.path模块.querystring模块 Url { protocol: null, slashes: null, auth: null, h ...