zoukankan      html  css  js  c++  java
  • bzoj 5329 [SDOI2018] 战略游戏

    bzoj 5329 [SDOI2018] 战略游戏

    Solution

    很容易想到虚树

    然后发现是一个图。。。

    现学圆方树,套上去,做完了(模板题?)

    就是直接上广义圆方树先把这玩意转换成一棵树,然后对当前询问建立虚树,断掉虚树里任何一个点都合法(包括不出现的点,指那些在某个点和其虚树上父亲之间的点),统计一下即可

    Code

    // Copyright lzt
    #include<stdio.h>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #include<vector>
    #include<map>
    #include<set>
    #include<cmath>
    #include<iostream>
    #include<queue>
    #include<string>
    #include<ctime>
    using namespace std;
    typedef long long ll;
    typedef std::pair<int, int> pii;
    typedef long double ld;
    typedef unsigned long long ull;
    typedef std::pair<long long, long long> pll;
    #define fi first
    #define se second
    #define pb push_back
    #define mp make_pair
    #define rep(i, j, k)  for (register int i = (int)(j); i <= (int)(k); i++)
    #define rrep(i, j, k) for (register int i = (int)(j); i >= (int)(k); i--)
    #define Debug(...) fprintf(stderr, __VA_ARGS__)
     
    inline ll read() {
      ll x = 0, f = 1;
      char ch = getchar();
      while (ch < '0' || ch > '9') {
        if (ch == '-') f = -1;
        ch = getchar();
      }
      while (ch <= '9' && ch >= '0') {
        x = 10 * x + ch - '0';
        ch = getchar();
      }
      return x * f;
    }
     
    const int maxn = 200200;
    int tc, n, m, Q, tot, tim;
    int dfn[maxn], low[maxn], S[maxn], s[maxn], q[maxn];
    int fa[maxn], dep[maxn], dis[maxn], sz[maxn], son[maxn], top[maxn];
     
    struct Graph {
      int head[maxn], to[maxn << 1], nxt[maxn << 1], tot;
      void init() {
        memset(head, 0, sizeof(head));
        tot = 0;
      }
      void addedge(int x, int y) {
        to[++tot] = y; nxt[tot] = head[x]; head[x] = tot;
        to[++tot] = x; nxt[tot] = head[y]; head[y] = tot;
      }
    } G1, G2;
     
    void Tarjan(int u) {
      tim++; dfn[u] = low[u] = tim; S[++S[0]] = u;
      for (int i = G1.head[u]; i; i = G1.nxt[i]) {
        int v = G1.to[i];
        if (!dfn[v]) {
          Tarjan(v); low[u] = min(low[u], low[v]);
          if (low[v] >= dfn[u]) { // 单独一条边连接两个点也得算作点双
            G2.addedge(++tot, u); int x = 0;
            do {
              x = S[S[0]]; S[0]--;
              G2.addedge(tot, x);
            } while (x != v);
          }
        }
        else low[u] = min(low[u], dfn[v]);
      }
    }
     
    void dfs1(int u, int pa) {
      fa[u] = pa; dep[u] = dep[pa] + 1; dis[u] = dis[pa] + (u <= n); sz[u] = 1;
      for (int i = G2.head[u]; i; i = G2.nxt[i]) {
        int v = G2.to[i];
        if (v == pa) continue;
        dfs1(v, u); sz[u] += sz[v];
        if (sz[v] > sz[son[u]]) son[u] = v;
      }
    }
     
    void dfs2(int u, int tp) {
      top[u] = tp; dfn[u] = ++tim;
      if (son[u]) dfs2(son[u], tp);
      for (int i = G2.head[u]; i; i = G2.nxt[i]) {
        int v = G2.to[i];
        if (v == fa[u] || v == son[u]) continue;
        dfs2(v, v);
      }
      low[u] = tim;
    }
     
    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]];
      }
      return dep[x] < dep[y] ? x : y;
    }
     
    bool cmp(int x, int y) {
      return dfn[x] < dfn[y];
    }
     
    void work() {
      tc = read();
      while (tc--) {
        n = read(), m = read(); G1.init(); G2.init(); tim = 0; tot = n;
        rep(i, 1, m) {
          int x = read(), y = read();
          G1.addedge(x, y);
        }
        memset(dfn, 0, sizeof(dfn));
        memset(son, 0, sizeof(son));
        rep(i, 1, n) if (!dfn[i]) Tarjan(i);
        tim = 0; dfs1(1, 0); dfs2(1, 1);
        Q = read();
        while (Q--) {
          int k = read(), len = k, tp = 0, ans = 0;
          rep(i, 1, k) s[i] = read();
          sort(s + 1, s + k + 1, cmp);
          rep(i, 1, k - 1) s[++len] = lca(s[i], s[i + 1]);
          sort(s + 1, s + len + 1, cmp);
          len = unique(s + 1, s + len + 1) - (s + 1);
          ans = s[1] <= n;
          rep(i, 1, len) {
            while (tp && low[q[tp]] < dfn[s[i]]) tp--;
            if (tp) ans += dis[s[i]] - dis[q[tp]];
            q[++tp] = s[i];
          }
          printf("%d
    ", ans - k);
        }
      }
    }
     
    int main() {
      #ifdef LZT
      freopen("in", "r", stdin);
      // freopen("out", "w", stdout);
      #endif
     
      work();
     
      #ifdef LZT
      Debug("My Time: %.3lfms
    ", (double)clock() / CLOCKS_PER_SEC);
      #endif
    }
    

    Review

    第一次写圆方树

    如果知道圆方树的话这题感觉很好想

  • 相关阅读:
    【java】详解java多线程
    【java】switch case支持的6种数据类型
    【Java】详解java对象的序列化
    【java】详解I/O流
    【java】自定义异常类
    【java】详解集合
    【NotePade++】NotePade++如何直接编译运行java文件
    【java】JVM的内存区域划分
    Unicode和UTF的关系
    【java】解析java中的数组
  • 原文地址:https://www.cnblogs.com/wawawa8/p/10162887.html
Copyright © 2011-2022 走看看