zoukankan      html  css  js  c++  java
  • 洛谷 P2633 Count on a tree

    思路

    看到路径上(k)小值,首先想到主席树

    不会主席树的建议来这里看一下【AgOHの数据结构】主席树(友情提示:此链接为B站视频

    但是这是棵树,并不是序列,我们应该怎么办呢?

    显然,我们可以像序列前缀和一样,建立树上前缀和:以点的(dfs)序为下标,以点权为区间建立主席树。

    那么查询时((x,y))这条链间的点数就是

    [sum[x]+sum[y]-sum[lca]-sum[fa[lca]] ]

    这里用到了一点点树上差分的思想,自己思考一下

    至于(LCA),用树剖或者倍增求一下就好了

    然后查询的时候就可以像序列上一样了

    代码

    /*
    Author:Loceaner
    */
    #include <cmath>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    const int A = 5e5 + 11;
    const int B = 1e6 + 11;
    const int mod = 1e9 + 7;
    const int inf = 0x3f3f3f3f;
    
    inline int read() {
      char c = getchar(); int x = 0, f = 1;
      for ( ; !isdigit(c); c = getchar()) if (c == '-') f = -1;
      for ( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
      return x * f;
    }
    
    struct node { int to, nxt; } e[A];
    int n, m, head[A], cnt/*边数*/, tcnt/*主席树数*/, tot/*离散化之后*/;
    int a[A], b[A], lastans; 
    
    inline void add(int from, int to) {
      e[++cnt].to = to;
      e[cnt].nxt = head[from];
      head[from] = cnt;
    }
    
    /*主席树*/
    int root[A];
    struct tree { int l, r, sum; } t[A * 10];
    
    inline int getid(int x) {
      return lower_bound(b + 1, b + 1 + tot, x) - b;
    }
    
    void insert(int &now, int pre, int l, int r, int pos) {
      t[++tcnt] = t[pre], t[now = tcnt].sum++;
      if (l == r) return;
      int mid = (l + r) >> 1;
      if (pos <= mid) insert(t[now].l, t[pre].l, l, mid, pos);
      else insert(t[now].r, t[pre].r, mid + 1, r, pos);
    }
    
    int query(int x, int y, int lca, int fa_lca, int l, int r, int k) {
      if (l == r) return l;
      int mid = (l + r) >> 1;
      int tmp = t[t[x].l].sum + t[t[y].l].sum - t[t[lca].l].sum - t[t[fa_lca].l].sum;
      if (k <= tmp) query(t[x].l, t[y].l, t[lca].l, t[fa_lca].l, l, mid, k);
      //debug:k<=tmp写成k>=tmp 
      else query(t[x].r, t[y].r, t[lca].r, t[fa_lca].r, mid + 1, r, k - tmp);
    }
    
    /*树剖*/
    int dep[A], fa[A], top[A], siz[A], son[A];
    
    void prepare(int x, int f) {
      dep[x] = dep[f] + 1, fa[x] = f, siz[x] = 1;
      insert(root[x], root[fa[x]], 1, n, getid(a[x]));
      for (int i = head[x]; i; i = e[i].nxt) {
        int to = e[i].to;
        if (to == f) continue;
        prepare(to, x), siz[x] += siz[to];
        //debug:prepare写成dfs 
        if (siz[to] > siz[son[x]]) son[x] = to;
      }
    }
    
    void dfs(int x, int tp) {
      top[x] = tp;
      if (son[x]) dfs(son[x], tp);
      for (int i = head[x]; i; i = e[i].nxt) {
        int to = e[i].to;
        if (to == fa[x] || to == son[x]) continue;
        dfs(to, to);
      }
    }
    
    int LCA(int x, int y) {
      while (top[x] != top[y]) {
        if (dep[top[x]] < dep[top[y]]) swap(x, y);
        x = fa[top[x]];
      }
      if (dep[x] > dep[y]) swap(x, y);
      return x;
    }
    
    int main() {
      n = read(), m = read();
      for (int i = 1; i <= n; i++) b[i] = a[i] = read();
      for (int i = 1; i < n; i++) {
        int x = read(), y = read();
        add(x, y), add(y, x);
      } 
      sort(b + 1, b + 1 + n);
      tot = unique(b + 1, b + 1 + n) - b - 1;
      prepare(1, 0), dfs(1, 1);
      while (m--) {
        int x = read(), y = read(), k = read();
        x ^= lastans;
        int lca = LCA(x, y);
        lastans = b[query(root[x], root[y], root[lca], root[fa[lca]], 1, n, k)];
        cout << lastans << '
    ';
      }
      return 0;
    }
    
  • 相关阅读:
    错误:you (root) are not allowed to access to (crontab) because of pam configuration.
    linux自定义登录提示信息
    oracle错误IMP-00013: only a DBA ……
    将MyBatis Mapper xml 放到 jar 包外面
    ApplicationContextAware
    Netty ChannelFuture 监听三种方法
    Intellij 查找排除JAR包的依赖关系(Maven Helper)
    Nacos 服务状态监听四种写发
    Docker 常用命令
    Nginx 安装配置
  • 原文地址:https://www.cnblogs.com/loceaner/p/13284834.html
Copyright © 2011-2022 走看看