一 题目

  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. POJ - 3280 Cheapest Palindrome 【区间dp】【非原创】

    Keeping track of all the cows can be a tricky task so Farmer John has installed a system to automate ...

  2. codeforces 2C(非原创)

    C. Commentator problem time limit per test 1 second memory limit per test 64 megabytes input standar ...

  3. Web 实时通信方案 All In One

    Web 实时通信方案 All In One HTTP 轮询, 单向通信,开销大 HTTP 长轮询, 单向通信,开销较小 WebSocket,双向通信,开销小 (TCP 高延迟,保证数据完整性) Ser ...

  4. node os env reader

    node os env reader node-os-env-reader.js #!/usr/bin/env node "use strict"; /** * * @author ...

  5. Flutter 1.17.x

    Flutter 1.17.x Flutter (Channel stable, v1.17.3, on Mac OS X 10.15.5 19F101, locale en-CN) https://f ...

  6. d3 & hexagon

    d3 & hexagon https://bl.ocks.org/mbostock/5249328 https://bl.ocks.org/vasturiano/e70e14483fe01eb ...

  7. SVG to GeoJSON

    SVG to GeoJSON GEOJSON https://geojson.org/ http://geojson.io/ https://github.com/mapbox/geojson.io/ ...

  8. Baccarat流动性挖矿的收益能否持续?该如何参与Baccarat流动性挖矿?

    2020年DeFi市场火热,众多投资机构纷纷入场,分享这场资本盛宴.然而,目前市面上大多数DeFi项目手续费高昂,小资金的投资者无法入市.为了让更多的用户参与其中,NGK推出了Baccarat流动性挖 ...

  9. [Python] Matplotlib 图表的绘制和美化技巧

    目录 在一张画布中绘制多个图表 加图表元素 气泡图 组合图 直方图 雷达图 树状图 箱形图 玫瑰图 在一张画布中绘制多个图表 Matplotlib模块在绘制图表时,默认先建立一张画布,然后在画布中显示 ...

  10. Mybatis高级:Mybatis注解开发单表操作,Mybatis注解开发多表操作,构建sql语句,综合案例学生管理系统使用接口注解方式优化

    知识点梳理 课堂讲义 一.Mybatis注解开发单表操作 *** 1.1 MyBatis的常用注解 之前我们在Mapper映射文件中编写的sql语句已经各种配置,其实是比较麻烦的 而这几年来注解开发越 ...