POJ 3237 树链剖分+线段树维护

和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. 在没有写线段树时交了一个树剖+暴力查询和更新的版本,结果跟用线段树维护的版本时间相差不多。。。

#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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值