SPOJ 375 QTREE - Query on a tree(树链剖分)

题目链接:http://www.spoj.com/problems/QTREE/en/

题意:  一棵树 n 个节点,每条边上有权值,同时有两个操作:

  (1)更改操作:CHANGE i ti(把第 i 条边上的权值改为 ti)。

  (2)查询操作:QUERY a b(查询 a 到 b 的路径上权值最大的边的权值)。

思路(树链剖分):

  看到这种区间查询的题想要用数据结构优化,提高时间效率一般会想到线段树。可是这次操作的对象并不是一组序列,

无法直接使用线段树。这时,我们可以做些转化:对树作树链剖分,就是把树剖开成为一条条链,这时一条链可以作为线段树的一段连续区间。

通过剖分,这些链包括了树的 n - 1 条边,把这些边一一映射到线段树中(重新编号),这样就可已实现对树上两个节点的区间查询了。

  那把树剖分成链有什么作用呢?

  首先看一下是如何剖分的:

  一些需要知道的名词:

    重儿子:对于父节点 u ,所有以 u 的子节点为根的子树中包含最多节点的那个子树的根 v 就是 u 的重儿子。

    轻儿子:父节点 u 所有的子节点中,不是重儿子的都是轻儿子。

    重边:重儿子 v 与其父节点 u 之间的边。

    轻边:轻儿子 v 与其父节点 u 之间的边。

    重链:由重边组成的链就是重链了。正是有了重链,对其的编号是从上到下连续的,所以我们在查询时才可以节省了很多时间。

  代码过程中,需要用到的数组(存储一些必要信息,经过 2 次 dfs 得到):

    第一次 dfs : fa(father,节点的父节点),size(已该节点为根的子树节点数量),deep(当前节点在树中的深度),son(当前节点的重儿子)。

    第二次 dfs : pos(position,树上的边在线段树上的位置),top(当前节点所在重链距离树根最近的节点)。

  重新编号?:

    第二次 dfs 过程中,对重儿子优先编号。因为是 dfs 保证了一条重链上的节点从上到下编号是连续递增的(对应线段树上的一段区间)。

这样我们的映射就完成了,可以对树作一定的查询了。

  对于一个查询 QUERY a b :

    (1)若 a,b 在同一条重链上:就可以直接在线段树上查询了(在同一个连续区间上)。

    (2)若不在同一条重链上:则只能查询 a,b 所在重链上节点对应的边,有一条不是重边。这样逐步查询,一直逼近 a,b 的 LCA(最近公共祖先)。

代码:

  1 #include <stdio.h>
  2 #include <string.h>
  3 #include <algorithm>
  4 #include <math.h>
  5 using namespace std;
  6
  7 const int N = 100007;
  8
  9 struct Edge
 10 {
 11     int to;
 12     int next;
 13     int w;
 14 }edge[N];
 15
 16 struct Node
 17 {
 18     int L;
 19     int R;
 20     int mid()
 21     {
 22         return (L + R) >> 1;
 23     }
 24     int maxn;
 25 }bT[N];
 26
 27 int cnt, e[N][3];
 28 int fa[N], head[N], size[N], son[N], top[N], deep[N], pos[N], fpos[N];
 29
 30 void addEdge(int u, int v, int w, int idx)
 31 {
 32     edge[idx].to = v;
 33     edge[idx].w = w;
 34     edge[idx].next = head[u];
 35     head[u] = idx;
 36 }
 37
 38 void dfs1(int u, int pre, int d) //deep, fa, son, size
 39 {
 40     deep[u] = d;
 41     fa[u] = pre;
 42     size[u] = 1;
 43     for (int r = head[u]; r != -1; r = edge[r].next)
 44     {
 45         int v = edge[r].to;
 46         if (v != pre)
 47         {
 48             dfs1(v, u, d + 1);
 49             size[u] += size[v];
 50             if (son[u] == -1 || size[v] > size[son[u]])
 51                 son[u] = v;
 52         }
 53     }
 54 }
 55
 56 void getpos(int u, int anc) //pos, fpos, top
 57 {
 58     top[u] = anc;
 59     pos[u] = cnt++;
 60     fpos[pos[u]] = u;
 61     if (son[u] == -1)
 62         return;
 63     getpos(son[u], anc);
 64     for (int r = head[u]; r != -1; r = edge[r].next)
 65     {
 66         int v = edge[r].to;
 67         if (v != fa[u] && son[u] != v)
 68             getpos(v, v);
 69     }
 70 }
 71
 72 void push_up(int i)   //线段树------begin-------
 73 {
 74     bT[i].maxn = max(bT[i<<1].maxn, bT[i<<1|1].maxn);
 75 }
 76
 77 void build(int L, int R, int i)
 78 {
 79     bT[i].L = L;
 80     bT[i].R = R;
 81     bT[i].maxn = 0;
 82     if (L == R)
 83         return;
 84     int mid = bT[i].mid();
 85     build(L, mid, i<<1);
 86     build(mid + 1, R, i<<1|1);
 87 }
 88
 89 void update(int l, int val, int i)
 90 {
 91     if (bT[i].L == l && bT[i].R == l)
 92     {
 93         bT[i].maxn = val;
 94         return;
 95     }
 96     int mid = bT[i].mid();
 97     if (l <= mid)
 98         update(l, val, i << 1);
 99     else
100         update(l, val, i<<1|1);
101     push_up(i);
102 }
103
104 int query(int l, int r, int i)  //--------end------
105 {
106     if (bT[i].L == l && bT[i].R == r)
107         return bT[i].maxn;
108     int mid = bT[i].mid();
109     if (r <= mid)
110         return query(l, r, i << 1);
111     if (l > mid)
112         return query(l, r, i<<1|1);
113     return max(query(l, mid, i<<1), query(mid + 1, r, i<<1|1));
114 }
115
116 int find(int u, int v)  //u,v的查询
117 {
118     int fu = top[u], fv = top[v], maxx = 0;
119     while (fu != fv)
120     {
121         if (deep[fu] < deep[fv])
122         {
123             swap(u, v);
124             swap(fu, fv);
125         }
126         maxx = max(maxx, query(pos[fu], pos[u], 1));
127         u = fa[fu];
128         fu = top[u];
129     }
130     if (u == v)
131         return maxx;
132     if (deep[u] > deep[v])
133         swap(u, v);
134     return max(maxx, query(pos[son[u]], pos[v], 1));
135 }
136
137 void init()
138 {
139     memset(size, 0, sizeof(size));
140     memset(head, -1, sizeof(head));
141     memset(son, -1, sizeof(son));
142 }
143
144 int main()
145 {
146     #ifndef ONLINE_JUDGE
147         freopen("in.ads","r",stdin);
148     #endif
149     char op[100];
150     int T, n;
151     while (scanf("%d", &T) != EOF)
152     {
153         while (T--)
154         {
155             scanf("%d", &n);
156             init();
157             for (int i = 0; i < n - 1; i++)
158             {
159                 scanf("%d%d%d", &e[i][0], &e[i][1], &e[i][2]);
160                 addEdge(e[i][0], e[i][1], e[i][2], 2 * i);
161                 addEdge(e[i][1], e[i][0], e[i][2], 2 * i + 1);
162             }
163             dfs1(1, 0, 0);
164             cnt = 0;
165             getpos(1, 1);
166             build(0, cnt - 1, 1);
167             for (int i = 0; i < n - 1; i++)
168             {
169                 if (deep[e[i][0]] > deep[e[i][1]])
170                     swap(e[i][0], e[i][1]);
171                 update(pos[e[i][1]], e[i][2], 1);
172             }
173             while (scanf("%s", op))
174             {
175                 int u, v;
176                 if (op[0] == ‘D‘)
177                     break;
178                 else if (op[0] == ‘C‘)
179                 {
180                     scanf("%d%d", &u, &v);
181                     update(pos[e[u-1][1]], v, 1);
182                 }
183                 else
184                 {
185                     scanf("%d%d", &u, &v);
186                     printf("%d\n", find(u, v));
187                 }
188                 getchar();
189             }
190         }
191     }
192     return 0;
193 }
时间: 2024-11-10 08:35:45

SPOJ 375 QTREE - Query on a tree(树链剖分)的相关文章

spoj 375 QTREE - Query on a tree 树链剖分

题目链接 给一棵树, 每条边有权值, 两种操作, 一种是将一条边的权值改变, 一种是询问u到v路径上最大的边的权值. 树链剖分模板. #include <iostream> #include <vector> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <map> #include <set&g

SPOJ QTREE Query on a tree ——树链剖分 线段树

[题目分析] 垃圾vjudge又挂了. 树链剖分裸题. 垃圾spoj,交了好几次,基本没改动却过了. [代码](自带常数,是别人的2倍左右) #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define maxn 20005 int T,n,fr[maxn],h[maxn],to[maxn],ne[maxn]

SPOJ QTREE Query on a tree --树链剖分

题意:给一棵树,每次更新某条边或者查询u->v路径上的边权最大值. 解法:做过上一题,这题就没太大问题了,以终点的标号作为边的标号,因为dfs只能给点分配位置,而一棵树每条树边的终点只有一个. 询问的时候,在从u找到v的过程中顺便查询到此为止的最大值即可. 代码: #include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> #include <cmath&

SPOJ - QTREE 375 Query on a tree 树链剖分+线段树

操作1:修改第k条边权. 操作2:询问两点间最大边权. 树链剖分,然后线段树维护最大值 #include<cstdio> #include<cstring> #include<cmath> #include<iostream> #include<algorithm> #include<set> #include<map> #include<queue> #include<vector> #inclu

SPOJ375 Query on a tree 树链剖分

SPOJ375  Query on a tree   树链剖分 no tags You are given a tree (an acyclic undirected connected graph) with N nodes, and edges numbered 1, 2, 3...N-1. We will ask you to perfrom some instructions of the following form: CHANGE i ti : change the cost of

spoj 375 Query on a tree (树链剖分)

Query on a tree You are given a tree (an acyclic undirected connected graph) with N nodes, and edges numbered 1, 2, 3...N-1. We will ask you to perfrom some instructions of the following form: CHANGE i ti : change the cost of the i-th edge to ti or Q

spoj Query on a tree(树链剖分模板题)

375. Query on a tree Problem code: QTREE You are given a tree (an acyclic undirected connected graph) with N nodes, and edges numbered 1, 2, 3...N-1. We will ask you to perfrom some instructions of the following form: CHANGE i ti : change the cost of

SPOJ Query on a tree 树链剖分 水题

You are given a tree (an acyclic undirected connected graph) with N nodes, and edges numbered 1, 2, 3...N-1. We will ask you to perfrom some instructions of the following form: CHANGE i ti : change the cost of the i-th edge to tior QUERY a b : ask fo

Query on a tree 树链剖分 [模板]

You are given a tree (an acyclic undirected connected graph) with N nodes, and edges numbered 1, 2, 3...N-1. We will ask you to perfrom some instructions of the following form: CHANGE i ti : change the cost of the i-th edge to ti or QUERY a b : ask f