BZOJ 3307

一棵n个点的树,m次操作,每次选择两个点x,y,往x到y的路径上每个点放一个z类型的物品。问最后每个点存放最多的是哪种物品。

\[n,m \leq 10^5 \]

树上差分然后线段树合并

const int MAXN = 100000 + 5, LOG = 60;

struct SegmentTree {
  struct Node {
    Node *ch[2];
    int max, num;
    
#define max(x) ((x) ? (x)->max : 0)
#define num(x) ((x) ? (x)->num : 0)
    void push_up() {
      max = max(ch[0]);
      num = num(ch[0]);
      if (chkmax(max, max(ch[1])))
        num = num(ch[1]);
    }
  } nd[MAXN * LOG], *pos;
  
  SegmentTree() {
    pos = nd;
  }
  
  Node *new_node() {
    pos->max = pos->num = 0;
    pos->ch[0] = pos->ch[1] = NULL;
    return pos ++;
  }
  
  void insert(Node *&o, int l, int r, int p, int x) {
    if (!o)
      o = new_node();
    if (l == r) {
      o->max += x;
      o->num = p;
      return;
    }
    int mid = (l + r) >> 1;
    if (p <= mid)
      insert(o->ch[0], l, mid, p, x);
    else
      insert(o->ch[1], mid + 1, r, p, x);
    o->push_up();
  }
  
  Node *merge(Node *&o, Node *&p, int l, int r) {
    if (!o || !p)
      return o ? o : p;
    if (l == r) {
      o->max += p->max;
      p = NULL;
      return o;
    }
    int mid = (l + r) >> 1;
    if (o->ch[0] || p->ch[0])
      o->ch[0] = merge(o->ch[0], p->ch[0], l, mid);
    if (o->ch[1] || p->ch[1])
      o->ch[1] = merge(o->ch[1], p->ch[1], mid + 1, r);
    p = NULL;
    o->push_up();
    return o;
  }
} Seg;

int ans[MAXN], lg[MAXN], n, m, sz;

struct Tree {
  int hed[MAXN], nxt[MAXN * 2], to[MAXN * 2], fa[LOG][MAXN], dep[MAXN], cnt;
  SegmentTree::Node *ptr[MAXN];
  
  void add_edge(int u, int v) {
    ++ cnt;
    to[cnt] = v;
    nxt[cnt] = hed[u];
    hed[u] = cnt;
  }
  
  void DFS1(int u) {
    for (int i = 1; 1 << i <= dep[u]; ++ i)
      fa[i][u] = fa[i - 1][fa[i - 1][u]];
    for (int e = hed[u]; e; e = nxt[e]) {
      int v = to[e];
      if (v != fa[0][u]) {
        fa[0][v] = u;
        dep[v] = dep[u] + 1;
        DFS1(v);
      }
    }
  }
  
  int LCA(int u, int v) {
    if (dep[u] < dep[v])
      std::swap(u, v);
    int del = dep[u] - dep[v];
    For(i, 0, lg[n])
      if (del & (1 << i))
        u = fa[i][u];
    if (u == v)
      return u;
    Rep(i, lg[n], 0)
      if (fa[i][u] != fa[i][v])
        u = fa[i][u], v = fa[i][v];
    return fa[0][u];
  }
  
  void DFS2(int u) {
    for (int e = hed[u]; e; e = nxt[e]) {
      int v = to[e];
      if (v != fa[0][u]) {
        DFS2(v);
        ptr[u] = Seg.merge(ptr[u], ptr[v], 1, sz);
      }
    }
    ans[u] = num(ptr[u]);
  }
} T;

struct Query {
  int u, v, z, p;
} q[MAXN];

int tmp[MAXN], to[MAXN];

int main() {
  scanf("%d%d", &n, &m);
  For(i, 2, n) {
    int u, v;
    scanf("%d%d", &u, &v);
    T.add_edge(u, v);
    T.add_edge(v, u);
  }
  lg[0] = -1;
  For(i, 1, n)
    lg[i] = lg[i >> 1] + 1;
  T.DFS1(1);
  For(i, 1, m) {
    scanf("%d%d%d", &q[i].u, &q[i].v, &q[i].z);
    tmp[i] = q[i].z;
  }
  std::sort(tmp + 1, tmp + m + 1);
  sz = std::unique(tmp + 1, tmp + m + 1) - tmp;
  For(i, 1, m) {
    q[i].p = std::lower_bound(tmp + 1, tmp + sz, q[i].z) - tmp;
    Seg.insert(T.ptr[q[i].u], 1, sz, q[i].p, 1);
    Seg.insert(T.ptr[q[i].v], 1, sz, q[i].p, 1);
    int lca = T.LCA(q[i].u, q[i].v);
    Seg.insert(T.ptr[lca], 1, sz, q[i].p, -1);
    Seg.insert(T.ptr[T.fa[0][lca]], 1, sz, q[i].p, -1);
    to[q[i].p] = q[i].z;
  }
  T.DFS2(1);
  For(i, 1, n)
    printf("%d\n", to[ans[i]]);
  return 0;
}
posted @ 2018-10-10 19:22  sjkmost  阅读(202)  评论(0编辑  收藏  举报