SPOJ QTree【树链剖分】

一 题目

  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
", find(u, v));
199         }
200     }
201     return 0;
202 }
View Code
原文地址:https://www.cnblogs.com/dybala21/p/10845331.html