zoukankan      html  css  js  c++  java
  • CF176E Archaeology

    CF176E Archaeology

    有一棵 (n) 个点的带权树,每个点都是黑色或白色,最初所有点都是白色的。有 (m) 个询问:

    • 把点 (x) 从白色变成黑色
    • 把点 (x) 从黑色变成白色
    • 查询黑点的导出子树的边权和

    (1 leq n, q leq 10^5, 1leq xleq n)

    LCA


    双倍经验 bzoj3991 [SDOI2015]寻宝游戏

    结论:

    • 按照时间戳把所有黑点升序排序,累加相邻及首尾两点之间的路径长度,最后得到的结果恰好是所求答案的两倍

    于是可以用一个数据结构按照时间戳递增的顺序维护黑点序列,算插/删点的贡献用 (lca) 维护

    这个数据结构需要支持插入、求前驱后继,直接用 (set) 就吼辣

    时间复杂度 (O(nlog n))

    代码

    #include <bits/stdc++.h>
    using namespace std;
    
    #define iter set <int> :: iterator
    typedef long long ll;
    const int maxn = 1e5 + 10;
    ll ans, dis[maxn];
    int n, m, tid[maxn], rk[maxn], h[maxn];
    int sz[maxn], fa[maxn], dep[maxn], son[maxn], top[maxn];
    
    set <int> seq;
    
    struct edges {
      int nxt, to, w;
    } e[maxn << 1];
    
    void addline(int u, int v, int w) {
      static int cnt = 1;
      e[++cnt] = edges{h[u], v, w}, h[u] = cnt;
    }
    
    int dfs1(int u, int f) {
      fa[u] = f, dep[u] = dep[f] + 1;
      for (int i = h[u]; i; i = e[i].nxt) {
        int v = e[i].to;
        if (v != f) {
          dis[v] = dis[u] + e[i].w;
          sz[u] += dfs1(v, u);
          if (sz[son[u]] < sz[v]) {
            son[u] = v;
          }
        }
      }
      return ++sz[u];
    }
    
    void dfs2(int u, int tp) {
      static int now;
      top[u] = tp;
      tid[u] = ++now, rk[now] = u;
      if (son[u]) dfs2(son[u], tp);
      for (int i = h[u]; i; i = e[i].nxt) {
        int v = e[i].to;
        if (v != fa[u] && v != son[u]) {
          dfs2(v, v);
        }
      }
    }
    
    ll lca(int u, int v) {
      ll res = dis[u] + dis[v];
      while (top[u] != top[v]) {
        if (dep[top[u]] > dep[top[v]]) {
          u = fa[top[u]];
        } else {
          v = fa[top[v]];
        }
      }
      int _lca = dep[u] < dep[v] ? u : v;
      return res - 2 * dis[_lca];
    }
    
    ll query(iter it) {
      iter pre = it, nxt = it;
      pre = it == seq.begin() ? seq.end() : it, pre--;
      if (++nxt == seq.end()) nxt = seq.begin();
      int l = rk[*pre], r = rk[*nxt], u = rk[*it];
      return lca(l, u) + lca(u, r) - lca(l, r);
    }
    
    int main() {
      scanf("%d", &n);
      for (int i = 1, u, v, w; i < n; i++) {
        scanf("%d %d %d", &u, &v, &w);
        addline(u, v, w), addline(v, u, w);
      }
      dfs1(1, 0), dfs2(1, 1);
      scanf("%d", &m);
      iter it, tmp;
      char c; int x;
      while (m--) {
        scanf("%s", &c);
        if (c == '?') {
          printf("%I64d
    ", ans >> 1);
          continue;
        }
        scanf("%d", &x);
        if (c == '+') {
          it = seq.insert(tid[x]).first;
          if (seq.size() > 2) {
            ans += query(it);
          } else if (seq.size() == 2) {
            tmp = it == seq.begin() ? ++it : seq.begin();
            ans = lca(rk[*tmp], x) << 1;
          }
        } else {
          it = seq.find(tid[x]);
          if (seq.size() > 2) {
            ans -= query(it);
          } else if (seq.size() == 2) {
            ans = 0;
          }
          seq.erase(tid[x]);
        }
      }
      return 0;
    }
    
  • 相关阅读:
    Android上传文件到服务器(转)
    Android -- 利用Broadcast开启Service(转)
    【转】实践最有效的提高Android Studio运行、编译速度方案
    Android Studio3.x新的依赖方式(implementation、api、compileOnly)
    Drawable子类之——StateListDrawable (选择器)
    解决android studio引用远程仓库下载慢(JCenter下载慢)
    跳槽季,面试官:能接受加班吗?
    PHP 底层的运行机制与原理
    PHP程序员如何突破成长瓶颈
    VirtualBox启动虚拟机报错0x80004005
  • 原文地址:https://www.cnblogs.com/Juanzhang/p/10584700.html
Copyright © 2011-2022 走看看