(树链剖分+线段树)POJ - 3237 Tree

前言:

一直听说树链剖分-树链剖分,现在见识一下,,,感觉不是很难0.0

看了一下kuangbin模板基本秒懂

对于点,按重边优先给予每个点一个编号,对于一条重链上的点,编号则是连续的,将所有编号映射到线段树上,即可进行一切区间操作。

对于边的处理,我们将所有边对应到这条边节点更深的那个点上即可。

如果需要的操作只有求和,和单点更新/区间更新,直接用树状数组也是可以的,可能常数大那么一点点。

如果还需要更加强大的操作,显然用splay树维护也是可以的。。

比如树链上所有权值翻转等等。。不过,,这样差不多应该就快到LCT了。。虽然自己不会。。

不过过几天就该看了。

题意:

一棵树,每条边有一个权值,三种操作:

1、改变第i条边权值为v

2、将节点a到节点b之间的边权值取反

3、查询a到b之间最大的边权值

 

分析:

显然就是普通的树链剖分和线段树

但是要记得pushdown,

而对于lazy标记rev,当传下去的时候,不应该直接赋值为1或者0,而应该直接取反,用异或即可。

 

代码:

  1 #include <math.h>
  2 #include <stdio.h>
  3 #include <stdlib.h>
  4 #include <string.h>
  5 #include <time.h>
  6 #include <algorithm>
  7 #include <iostream>
  8 #include <map>
  9 #include <queue>
 10 #include <set>
 11 #include <string>
 12 #include <vector>
 13 using namespace std;
 14 
 15 const int maxn = 100010;
 16 const int inf = 0x3f3f3f3f;
 17 
 18 struct Edge {
 19     int to, next;
 20 } edge[maxn << 1];
 21 
 22 int head[maxn], tot;
 23 int top[maxn];
 24 int fa[maxn];
 25 int deep[maxn];
 26 int num[maxn];
 27 int p[maxn];
 28 int fp[maxn];
 29 int son[maxn];
 30 int pos;
 31 
 32 void init() {
 33     tot = 0;
 34     memset(head, -1, sizeof head);
 35     pos = 0;
 36     memset(son, -1, sizeof son);
 37 }
 38 
 39 void addedge(int u, int v) {
 40     edge[tot].to = v;
 41     edge[tot].next = head[u];
 42     head[u] = tot++;
 43 }
 44 void dfs1(int u, int pre, int d) {
 45     deep[u] = d;
 46     fa[u] = pre;
 47     num[u] = 1;
 48     for (int i = head[u]; i != -1; i = edge[i].next) {
 49         int v = edge[i].to;
 50         if (v != pre) {
 51             dfs1(v, u, d + 1);
 52             num[u] += num[v];
 53             if (son[u] == -1 || num[v] > num[son[u]]) son[u] = v;
 54         }
 55     }
 56 }
 57 
 58 void getpos(int u, int sp) {
 59     top[u] = sp;
 60     p[u] = pos++;
 61     fp[p[u]] = u;
 62     if (son[u] == -1) return;
 63     getpos(son[u], sp);
 64     for (int i = head[u]; i != -1; i = edge[i].next) {
 65         int v = edge[i].to;
 66         if (v != son[u] && v != fa[u]) getpos(v, v);
 67     }
 68 }
 69 
 70 struct Node {
 71     int left, right, maxs, mins;
 72     int rev;
 73 } node[maxn << 2];
 74 
 75 void build(int n, int left, int right) {
 76     node[n].left = left;
 77     node[n].right = right;
 78     node[n].maxs = 0;
 79     node[n].mins = 0;
 80     node[n].rev = 0;
 81     if (left == right) return;
 82     int mid = (left + right) >> 1;
 83     build(n << 1, left, mid);
 84     build(n << 1 | 1, mid + 1, right);
 85 }
 86 
 87 void push_up(int n) {
 88     node[n].maxs = max(node[n << 1].maxs, node[n << 1 | 1].maxs);
 89     node[n].mins = min(node[n << 1].mins, node[n << 1 | 1].mins);
 90 }
 91 
 92 void push_down(int n) {
 93     if (node[n].left == node[n].right) return;
 94     if (node[n].rev) {
 95         node[n << 1].rev ^= 1;
 96         node[n << 1 | 1].rev ^= 1;
 97         swap(node[n << 1].mins, node[n << 1].maxs);
 98         node[n << 1].mins *= -1;
 99         node[n << 1].maxs *= -1;
100         swap(node[n << 1 | 1].mins, node[n << 1 | 1].maxs);
101         node[n << 1 | 1].mins *= -1;
102         node[n << 1 | 1].maxs *= -1;
103         node[n].rev = 0;
104     }
105 }
106 
107 void update(int n, int pos, int val) {
108     if (node[n].left == node[n].right) {
109         node[n].maxs = val;
110         node[n].mins = val;
111         node[n].rev = 0;
112         return;
113     }
114     push_down(n);
115     int mid = (node[n].left + node[n].right) >> 1;
116     if (pos <= mid)
117         update(n << 1, pos, val);
118     else
119         update(n << 1 | 1, pos, val);
120     push_up(n);
121 }
122 
123 void Rev(int n, int left, int right) {
124     if (left <= node[n].left && node[n].right <= right) {
125         node[n].rev ^= 1;
126         swap(node[n].mins, node[n].maxs);
127         node[n].mins *= -1;
128         node[n].maxs *= -1;
129         return;
130     }
131     push_down(n);
132     int mid = (node[n].left + node[n].right) >> 1;
133     if (mid >= left) Rev(n << 1, left, right);
134     if (mid < right) Rev(n << 1 | 1, left, right);
135     push_up(n);
136 }
137 
138 int query(int n, int left, int right) {
139     if (left <= node[n].left && node[n].right <= right) {
140         return node[n].maxs;
141     }
142     push_down(n);
143     int mid = (node[n].left + node[n].right) >> 1;
144     int maxs = -inf;
145     if (mid >= left) maxs = max(maxs, query(n << 1, left, right));
146     if (mid < right) maxs = max(maxs, query(n << 1 | 1, left, right));
147     push_up(n);
148     return maxs;
149 }
150 
151 int findMax(int u, int v) {
152     int f1 = top[u], f2 = top[v];
153     int tmp = -inf;
154     while (f1 != f2) {
155         if (deep[f1] < deep[f2]) {
156             swap(f1, f2);
157             swap(u, v);
158         }
159         tmp = max(tmp, query(1, p[f1], p[u]));
160         u = fa[f1];
161         f1 = top[u];
162     }
163     if (u == v) return tmp;
164     if (deep[u] > deep[v]) swap(u, v);
165     return max(tmp, query(1, p[son[u]], p[v]));
166 }
167 
168 void Negate(int u, int v) {
169     int f1 = top[u], f2 = top[v];
170     while (f1 != f2) {
171         if (deep[f1] < deep[f2]) {
172             swap(f1, f2);
173             swap(u, v);
174         }
175         Rev(1, p[f1], p[u]);
176         u = fa[f1];
177         f1 = top[u];
178     }
179     if (u == v) return;
180     if (deep[u] > deep[v]) swap(u, v);
181     Rev(1, p[son[u]], p[v]);
182 }
183 
184 int e[maxn][3];
185 
186 int main() {
187     // freopen("1.out", "w", stdout);
188     int t;
189     int n;
190     scanf("%d", &t);
191     while (t--) {
192         init();
193         scanf("%d", &n);
194         for (int i = 0; i < n - 1; i++) {
195             int u, v, c;
196             scanf("%d%d%d", &e[i][0], &e[i][1], &e[i][2]);
197             addedge(e[i][0], e[i][1]);
198             addedge(e[i][1], e[i][0]);
199         }
200         dfs1(1, 0, 0);
201         getpos(1, 1);
202         build(1, 0, pos - 1);
203         for (int i = 0; i < n - 1; i++) {
204             if (deep[e[i][0]] > deep[e[i][1]]) swap(e[i][0], e[i][1]);
205             update(1, p[e[i][1]], e[i][2]);
206         }
207         char op[10];
208         int u, v;
209         while (scanf("%s", op)) {
210             if (op[0] == 'D') break;
211             scanf("%d%d", &u, &v);
212             if (op[0] == 'Q')
213                 printf("%d\n", findMax(u, v));
214             else if (op[0] == 'N') {
215                 Negate(u, v);
216             } else {
217                 update(1, p[e[u - 1][1]], v);
218             }
219         }
220     }
221     return 0;
222 }

 

转载于:https://www.cnblogs.com/tak-fate/p/7190244.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值