• [bzoj4551][Tjoi2016&Heoi2016]树-树链剖分


    Brief Description

    给定一颗有根树(根为1),有以下
    两种操作:1. 标记操作:对某个结点打上标记(在最开始,只有结点1有标记,其他结点均无标记,而且对于某个
    结点,可以打多次标记。)2. 询问操作:询问某个结点最近的一个打了标记的祖先(这个结点本身也算自己的祖
    先)你能帮帮他吗?

    Algorithm Design

    树链剖分维护最深层带标记节点.
    裸, 1A, 高兴.

    Code

    #include <cstdio>
    #define init int l = t[k].l, r = t[k].r, mid = (l + r) >> 1
    const int maxn = 201000;
    int n, Q, cnt;
    struct edge {
      int to, next;
    } e[maxn << 1];
    struct seg {
      int l, r, data;
    } t[maxn << 2];
    int head[maxn], q[maxn], bl[maxn], belong[maxn], size[maxn], dfn, like[maxn],
        tag[maxn], fa[maxn], deep[maxn];
    void add_edge(int u, int v) {
      e[++cnt].to = v;
      e[cnt].next = head[u];
      head[u] = cnt;
    }
    void dfs1(int x) {
      size[x] = 1;
      for (int i = head[x]; i; i = e[i].next) {
        if (e[i].to != fa[x]) {
          fa[e[i].to] = x;
          deep[e[i].to] = deep[x] + 1;
          dfs1(e[i].to);
          size[x] += size[e[i].to];
          if (size[e[i].to] > size[like[x]])
            like[x] = e[i].to;
        }
      }
    }
    void dfs2(int x, int chain) {
      bl[x] = ++dfn;
      q[dfn] = x;
      belong[x] = chain;
      if (like[x])
        dfs2(like[x], chain);
      for (int i = head[x]; i; i = e[i].next) {
        if (e[i].to != fa[x] && e[i].to != like[x]) {
          dfs2(e[i].to, e[i].to);
        }
      }
    }
    void build(int k, int l, int r) {
      t[k].l = l, t[k].r = r, t[k].data = (l <= 1 && 1 <= r) ? 1 : 0;
      if (l == r)
        return;
      int mid = (l + r) >> 1;
      build(k << 1, l, mid);
      build(k << 1 | 1, mid + 1, r);
    }
    void update(int k) {
      t[k].data = t[k << 1 | 1].data ? t[k << 1 | 1].data : t[k << 1].data;
    }
    void modify(int k, int pos, int val) {
      init;
      if (l == r) {
        if (deep[val] > deep[t[k].data])
          t[k].data = val;
        return;
      }
      if (pos <= mid)
        modify(k << 1, pos, val);
      else
        modify(k << 1 | 1, pos, val);
      update(k);
    }
    int query(int k, int x, int y) {
      init;
      if (x <= l && r <= y) {
        return t[k].data;
      }
      int ans = 0;
      if (x <= mid) {
        int t = query(k << 1, x, y);
        if (deep[t] > deep[ans])
          ans = t;
      }
      if (y > mid) {
        int t = query(k << 1 | 1, x, y);
        if (deep[t] > deep[ans])
          ans = t;
      }
      return ans;
    }
    void ask(int x, int f) {
      int ans = 0;
      while (belong[x] != belong[f]) {
        int t = query(1, bl[belong[x]], bl[x]);
        ans = t ? t : 0;
        if (ans)
          break;
        x = fa[belong[x]];
      }
      int t = query(1, bl[belong[x]], bl[x]);
      ans = t ? t : 0;
      printf("%d
    ", ans);
    }
    int main() {
    #ifndef ONLINE_JUDGE
      freopen("input", "r", stdin);
    #endif
      scanf("%d %d", &n, &Q);
      deep[0] = -1;
      for (int i = 1; i < n; i++) {
        int x, y;
        scanf("%d %d", &x, &y);
        add_edge(x, y);
        add_edge(y, x);
      }
      dfs1(1);
      dfs2(1, 1);
      build(1, 1, dfn);
      while (Q--) {
        char op[5];
        scanf("%s", op);
        if (op[0] == 'Q') {
          int x;
          scanf("%d", &x);
          ask(x, 1);
        } else {
          int x;
          scanf("%d", &x);
          tag[x] = 1;
          modify(1, bl[x], x);
        }
      }
    }
    
  • 相关阅读:
    微信获取openid过滤黑名单_写入文件_多协程版5500条10几秒
    微信获取openid写入文件golang版_golang获取微信openid写入文件
    go开发桌面应用源码_go Socket_golang Socket_golang开发桌面应用源码_go客户端服务端
    go常用代码片段_golang常用代码
    go基本语法_golang基本语法
    Java常用集合-List(ArrayList、Vector和LinkedList)简介
    mysql sql 将性别1和2转换成女和男
    支付宝当面付Demo测试
    PageResult
    返回结果
  • 原文地址:https://www.cnblogs.com/gengchen/p/6612465.html
Copyright © 2020-2023  润新知