zoukankan      html  css  js  c++  java
  • [CF1168D]Anagram Paths

    题意:给一棵(n)个节点的二叉树,每条边上有一个小写字母或者(?)(q)次修改操作,每次修改某条边上的字符,问修改后是否存在一种方案,使得给所有(?)填上小写字母后,所有叶子到根的路径字符串经重排后是否能全部相同,若能,还需要求出每种字符在这个字符串里的最多出现次数。

    题解:考虑怎样处理单次询问。

    首先显然每个叶子节点的深度必须是一样的,记为(dep)

    初步的想法显然是计算出根到每个叶子节点中每一种字符((?)除外)出现的最大次数,设(26)种字符出现的最大次数总和为(sum),那么有合法方案当且仅当(dep le sum)。但是这样是假的,因为(?)不独立。考虑修改上述算法,其实只要对以每一个节点为根的子树都用上述算法判断一遍是否合法即可。

    证明:必要性显然。

    充分性只要证明,对于任意一种最终的字符串,只要对于每个字符都满足字符串中这种字符的出现次数(ge)每条根到叶子的路径中这种字符出现的最大次数,那么就是一个合法的字符串。这能很容易地通过按树深度归纳证明。

    以上证明过程也告诉了我们怎样计算最大出现次数。

    考虑怎样处理修改。显然可以ddp可以发现,对于只有一个儿子的节点,可以把它和儿子缩起来。这样树的深度会变成(O(sqrt n))级别的。证明:设(s_i)为深度为(i)的节点数,那么第(i)层没有被缩完的话需要满足(s_i>s_{i-1}),所以最坏情况下(s=1,2,3,...,O(sqrt n))。因为保证了最大度数为(2),所以更新dp值的时候暴力就可以了。

    #include<bits/stdc++.h>
    using namespace std;
    const int N = 150010;
    typedef vector<int> vi;
    #define pb push_back
    
    int gi() {
      int x = 0, o = 1;
      char ch = getchar();
      while((ch < '0' || ch > '9') && ch != '-') {
        ch = getchar();
      }
      if(ch == '-') {
        o = -1, ch = getchar();
      }
      while(ch >= '0' && ch <= '9') {
        x = x * 10 + ch - '0', ch = getchar();
      }
      return x * o;
    }
    
    int n, q, fa[N], len[N], id[N], cnt[N][26], ban = 0, sum[N], f[N][26];
    vi E[N], G[N];
    char c[N];
    
    int dfs(int u) {
      int son = 0;
      for(auto v : E[u]) {
        ++son;
        dfs(v);
        if(len[u] && len[u] != len[v] + 1) {
          while(q--) {
            puts("Fou");
          }
          exit(0);
        }
        len[u] = len[v] + 1;
        id[u] = id[v];
      }
      if(son != 1 || !u) {
        id[u] = u;
        for(auto v : E[u]) {
          fa[id[v]] = u, G[u].pb(id[v]);
        }
      }
      return id[u];
    }
    
    void upd(int u, int c, int w) {
      cnt[u][c] += w;
      for(int x = fa[u]; ~x; x = fa[x]) {
        ban -= sum[x] > len[x];
        sum[x] -= f[x][c];
        f[x][c] = 0;
        for(auto v : G[x]) {
          f[x][c] = max(f[x][c], f[v][c] + cnt[v][c]);
        }
        sum[x] += f[x][c];
        ban += sum[x] > len[x];
      }
    }
    
    int main() {
    #ifndef ONLINE_JUDGE
      freopen("a.in", "r", stdin);
      freopen("a.out", "w", stdout);
    #endif
      cin >> n >> q;
      for(int i = 2; i <= n; i++) {
        E[gi()].pb(i), c[i] = getchar();
      }
      E[0].pb(1);
      dfs(0);
      --len[0];
      fa[0] = -1;
      for(int i = 2; i <= n; i++) if(c[i] != '?') {
          upd(id[i], c[i] - 'a', 1);
        }
      while(q--) {
        int u = gi();
        if(c[u] != '?') {
          upd(id[u], c[u] - 'a', -1);
        }
        c[u] = getchar();
        if(c[u] != '?') {
          upd(id[u], c[u] - 'a', 1);
        }
        if(ban) {
          puts("Fou");
        } else {
          cout << "Shi ";
          int ans = 0;
          for(int i = 0; i < 26; i++) {
            ans += (i + 1) * (f[0][i] + len[0] - sum[0]);
          }
          cout << ans << '
    ';
        }
      }
      return 0;
    }
    
    
  • 相关阅读:
    git add后 有的文件后悔 add了还没有commit 怎么办?
    go mod module declares its path as: gtihub.com/xxx-xx but was required as:xx-xx
    mysql 复合索引(联合索引) a b c的使用
    git 的初始化使用
    Mac 安装 mysql5.7
    Go Modules与GOPROXY 配置
    ZWWL的短信详设
    Linux 查看文件权限命令ls -l 输出信息每列所代表的含义
    ubuntu/deepin 下增加 goland 桌面快捷方式 goland.desktop
    go语言的冒泡 选择 快排 二分 算法实现
  • 原文地址:https://www.cnblogs.com/gczdajuruo/p/10933880.html
Copyright © 2011-2022 走看看