zoukankan      html  css  js  c++  java
  • 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
    ", to[ans[i]]);
      return 0;
    }
    
  • 相关阅读:
    内核笔记之内存寻址
    熟悉了HDFS的基本架构,了解这方面的专业术语(持续更新)
    第一步:ubuntu下android实验环境的建立,以及真机调试环境搭建
    关于hadoop的一些研究优化方向
    第三步:熟悉android的相关控件
    第一步系统环境的搭建
    第二步:关于布局文件中的大小设置使用问题
    Hibernate笔记
    Java学习之路——用dom4j解析xml
    利用Servlet和jsp实现客户端与服务器端的用户登录信息验证
  • 原文地址:https://www.cnblogs.com/sjkmost/p/9768474.html
Copyright © 2011-2022 走看看