POJ 3237 树链剖分+线段树维护
2018-02-28 17:21
218 查看
和QTREE1类似,增加了NEGATE操作。
记几个踩到的坑:
1. 维护数据量为n(假设n为2的幂)的线段树的大小为2*n-1,此题线段树的数组大小应为2^15-1,在写的时候写成1<<15-1,C++的<<的优先级小于-,实际开出来是2^14。
2. 这样写之后没有数组越界的异常,而是不断的WA。全局变量的内存分配在堆区,虽然访问的范围超过了数组的大小,但是在此数组之后还有其他数组的分配空间,导致线段树的更新和修改访问了其他用途的数组,导致了不断的WA。
3. 关于C++数组越界:假设有一个数组int a[5],访问a[10],a[100],a[1000]都可能不会产生越界的异常,越界异常的产生可能是访问的地址超过了操作系统给程序分配的段的范围(?),也就是说要足够大的数组下标才能触发异常。
4. 线段树的lazy tag:之前用lazy tag表示当前结点k未更新,另一种含义是当前结点的两个孩子未更新,按第二种含义来定义此题的取反标记会好写不少。
5. 在没有写线段树时交了一个树剖+暴力查询和更新的版本,结果跟用线段树维护的版本时间相差不多。。。
记几个踩到的坑:
1. 维护数据量为n(假设n为2的幂)的线段树的大小为2*n-1,此题线段树的数组大小应为2^15-1,在写的时候写成1<<15-1,C++的<<的优先级小于-,实际开出来是2^14。
2. 这样写之后没有数组越界的异常,而是不断的WA。全局变量的内存分配在堆区,虽然访问的范围超过了数组的大小,但是在此数组之后还有其他数组的分配空间,导致线段树的更新和修改访问了其他用途的数组,导致了不断的WA。
3. 关于C++数组越界:假设有一个数组int a[5],访问a[10],a[100],a[1000]都可能不会产生越界的异常,越界异常的产生可能是访问的地址超过了操作系统给程序分配的段的范围(?),也就是说要足够大的数组下标才能触发异常。
4. 线段树的lazy tag:之前用lazy tag表示当前结点k未更新,另一种含义是当前结点的两个孩子未更新,按第二种含义来定义此题的取反标记会好写不少。
5. 在没有写线段树时交了一个树剖+暴力查询和更新的版本,结果跟用线段树维护的版本时间相差不多。。。
#include <iostream> #include <vector> #include <string> #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <cassert> using namespace std; const int MAX_N = 10000 + 10; const int ST_SIZE = 1 << 15; const int INF = ~0U >> 1; // memset INF should be careful int dat[MAX_N], mi[ST_SIZE], mx[ST_SIZE], neg[ST_SIZE]; struct SegTree { // update the node k itself // the lazy tag means k's two children hasn't been updated void neg_it(int k) { swap(mi[k], mx[k]); mi[k] = -mi[k]; mx[k] = -mx[k]; neg[k] ^= 1; } void push_up(int k, int lc, int rc) { mi[k] = min(mi[lc], mi[rc]); mx[k] = max(mx[lc], mx[rc]); } // update k's two children lc and rc, push the lazy tag down // k must have two children, lc and rc won't be illegal void push_down(int k, int lc, int rc) { if (neg[k]) { neg_it(lc); neg_it(rc); neg[k] = 0; } } void init(int k, int l, int r) { if (l == r - 1) { mi[k] = dat[l]; mx[k] = dat[l]; neg[k] = 0; return; } int m = (l + r) / 2, lc = 2 * k + 1, rc = 2 * k + 2; init(lc, l, m); init(rc, m, r); push_up(k, lc, rc); neg[k] = 0; // forget to set neg here } void change(int k, int l, int r, int a, int c) { if (a < l || r <= a) return; if (l == r - 1) { mi[k] = c; mx[k] = c; return; } int m = (l + r) / 2, lc = 2 * k + 1, rc = 2 * k + 2; push_down(k, lc, rc); change(lc, l, m, a, c); change(rc, m, r, a, c); push_up(k, lc, rc); } void negate(int k, int l, int r, int a, int b) { if (b <= l || r <= a) return; if (a <= l && r <= b) { neg_it(k); return; } int m = (l + r) / 2, lc = 2 * k + 1, rc = 2 * k + 2; push_down(k, lc, rc); negate(lc, l, m, a, b); negate(rc, m, r, a, b); push_up(k, lc, rc); } int query(int k, int l, int r, int a, int b) { if (b <= l || r <= a) return -INF; if (a <= l && r <= b) return mx[k]; int m = (l + r) / 2, lc = 2 * k + 1, rc = 2 * k + 2; push_down(k, lc, rc); return max(query(lc, l, m, a, b), query(rc, m, r, a, b)); } } rmq; struct Edge { int to, cost; Edge* next; } epool[MAX_N * 2], *C, *head[MAX_N]; int es[MAX_N][3]; void add_edge(int from, int to, int cost) { C->to = to; C->cost = cost; C->next = head[from]; head[from] = C++; } // heavy light decomposition int N; int parent[MAX_N], depth[MAX_N], size[MAX_N], h[MAX_N]; int top[MAX_N], pos[MAX_N], tot; void init() { C = epool; memset(head, 0, sizeof(head)); memset(h, 0, sizeof(h)); tot = 0; } void dfs(int v, int p) { parent[v] = p; size[v] = 1; for (Edge* e = head[v]; e; e = e->next) { int u = e->to; if (u != p) { depth[u] = depth[v] + 1; dfs(u, v); size[v] += size[u]; if (h[v] == 0 || size[u] > size[h[v]]) h[v] = u; } } } void dfs2(int v, int tp) { top[v] = tp; pos[v] = tot++; if (h[v]) dfs2(h[v], tp); for (Edge* e = head[v]; e; e = e->next) { int u = e->to; if (u != parent[v] && u != h[v]) { dfs2(u, u); } } } void change(int i, int c) { rmq.change(0, 1, N, pos[es[i][0]], c); } void build() { int root = (N + 1) / 2; depth[root] = 0; dfs(root, -1); dfs2(root, root); // rmq.init(0, 1, N); for (int i = 1; i < N; i++) { int &u = es[i][0], &v = es[i][1]; if (depth[u] < depth[v]) swap(u, v); dat[pos[u]] = es[i][2]; // change(i, es[i][2]); } rmq.init(0, 1, N); } void neg_path(int u, int v) { int tu = top[u], tv = top[v]; while (tu != tv) { if (depth[tu] < depth[tv]) { swap(tu, tv); swap(u, v); } rmq.negate(0, 1, N, pos[tu], pos[u] + 1); u = parent[tu], tu = top[u]; } if (u != v) { if (depth[u] < depth[v]) swap(u, v); rmq.negate(0, 1, N, pos[h[v]], pos[u] + 1); } } int query(int u, int v) { int res = -INF; int tu = top[u], tv = top[v]; while (tu != tv) { if (depth[tu] < depth[tv]) { swap(tu, tv); swap(u, v); } res = max(res, rmq.query(0, 1, N, pos[tu], pos[u] + 1)); u = parent[tu], tu = top[u]; } if (u != v) { if (depth[u] < depth[v]) swap(u, v); res = max(res, rmq.query(0, 1, N, pos[h[v]], pos[u] + 1)); } return res; } int main() { int t; scanf("%d", &t); while (t--) { init(); scanf("%d", &N); int a, b, c; for (int i = 1; i < N; i++) { scanf("%d %d %d", &a, &b, &c); add_edge(a, b, c); add_edge(b, a, c); es[i][0] = a, es[i][1] = b, es[i][2] = c; } build(); char cmd[10]; while (scanf("%s", cmd) != EOF && cmd[0] != 'D') { scanf("%d %d", &a, &b); if (cmd[0] == 'Q') { printf("%d\n", query(a, b)); } else if (cmd[0] == 'N') { neg_path(a, b); } else { change(a, b); } } } return 0; }
相关文章推荐
- poj 3237 树链剖分+线段树
- POJ 3237 树链剖分+数据结构维护 题解
- poj 3237(树链剖分+线段树)
- POJ-3237(树链剖分+线段树)
- POJ 2763 树链剖分+线段树维护区间和
- POJ 3237 Tree(树链剖分+线段树)
- POJ 3237 Tree (树链剖分+线段树)
- POJ 3237 Tree(树链剖分+线段树)
- POJ 3237 Tree (树链剖分+线段树)
- POJ 3237 Tree (树链剖分+线段树)
- POJ 3237(树链剖分)
- poj 3237 Tree 树链剖分
- POJ 3321 Apple Tree(后根遍历将树转化成序列,用树状数组维护)
- POJ 3237 Tree (树链剖分)
- POJ 2828 Buy Tickets(线段树单点更新维护)
- poj 1456 Supermarket(并查集维护区间)
- POJ-3237:Tree(树链剖分)
- POJ 3237 Tree (树链剖分)
- POJ1442 Black Box 优先队列(堆维护)+思维
- poj-3237(树链剖分)