zoukankan      html  css  js  c++  java
  • CF587F Duff is Mad [AC自动机,离线根号分治,树状数组]

    题意:

    here
    (s_{[l,r]})(s_k) 的出现次数

    很妙的一道题。

    我们考虑到 (AC) 自动机的本质。

    (k) 的子树里都是包含 (s_k) 的串。
    (k) 的子树查询就相当于查询 (s_k) 出现了几次。

    然后我们发现。
    这个显然可以根号分治,大于 (sqrt {sum len_i}) 的和小于 (sqrt {sum len_i}) 的分别处理。

    如果暴力做,是把 (s_k) 每个点设置成 (1),然后 (l) ~ (r) 都查询一遍子树和。
    这样复杂度很高,但是可以拿来用。
    我们对于 (|s_k| geq sqrt {sum len_i}) 的,就把 (l) ~ (r) 记录一遍前缀和,相减就是。

    我们考虑一下 (s_k leq sqrt {sum len_i}) 的。

    我们如何改变子树查询呢?

    我们查询 (l) ~ (r) 都是查询子树对吧。

    然后我们发现,你查询子树,其实无异于增加子树然后把 (s_k) 的贡献加进去。
    简单来说呢,就是你可以计算出来每个点的覆盖次数,然后加进答案就好了。

    然后这题没了。

    #include <bits/stdc++.h>
    
    int read() {
      int x = 0;
      char c = getchar();
      while (c < 48) c = getchar();
      while (c > 47) x = x * 10 + (c - 48), c = getchar();
      return x;
    }
    
    using namespace std;
    #define int long long
    
    const int maxn = 1e5 + 51;
    char s[maxn];
    
    int n, q, S;
    vector<pair<int, int>> L[maxn], R[maxn], le[maxn], ri[maxn];
    int len[maxn], tot, ans[maxn];
    
    struct BIT {
      int c[maxn];
    
      BIT() { memset(c, 0, sizeof(c)); }
    
      int low(int x) { return x & -x; }
    
      void add(int x, int y) {
        for (; x < maxn; x += low(x)) c[x] += y;
      }
    
      int qry(int x) {
        int ans = 0;
        for (; x; x ^= low(x)) ans += c[x];
        return ans;
      }
    } bit;
    
    struct ACAM {
      int ch[maxn][26], cnt, ed[maxn], fail[maxn], fa[maxn] ;
    	
      ACAM() { cnt = 1; }
      
    	vector<int> g[maxn];
    	
      void ins(const int& len, const int& id) {
        int p = 1;
        for (int i = 1; i <= len; i++) {
          int c = s[i] - 'a';
          if (!ch[p][c]) ch[p][c] = ++cnt, fa[cnt] = p;
          p = ch[p][c];
        }
        ed[id] = p;
      }
    
      void build() {
        queue<int> q;
        for (int i = 0; i < 26; i++)
          if (ch[1][i])
            fail[ch[1][i]] = 1, q.push(ch[1][i]);
          else
            ch[1][i] = 1;
        while (q.size()) {
          int u = q.front();
          q.pop();
          for (int i = 0; i < 26; i++) {
            if (ch[u][i]) {
              fail[ch[u][i]] = ch[fail[u]][i];
              q.push(ch[u][i]);
            } else {
              ch[u][i] = ch[fail[u]][i];
            }
          }
        }
    
        for (int i = 2; i <= cnt; i++) g[fail[i]].push_back(i);
      }
    
    	
      int sz[maxn], dfn[maxn], idx = 0;
      
      void dfs1(int u) {
        for (int v : g[u]) dfs1(v), sz[u] += sz[v];
      }
    
      void dfs2(int u) {
        sz[u] = 1, dfn[u] = ++idx;
        for (int v : g[u]) dfs2(v), sz[u] += sz[v];
      }
    
      void solve() {
        for (int i = 1; i <= n; i++) {
          if (len[i] > S) {
            int p = ed[i];
            memset(sz, 0, sizeof(sz));
            while (p ^ 1) {
              sz[p] = 1, p = fa[p];
            }
            dfs1(1);
            sort(L[i].begin(), L[i].end()), sort(R[i].begin(), R[i].end());
            reverse(L[i].begin(), L[i].end()), reverse(R[i].begin(), R[i].end());
            int qwq = 0;
            for (int j = 1; j <= n; j++) {
              while (L[i].size() && L[i].back().first == j) ans[L[i].back().second] -= qwq, L[i].pop_back();
              qwq += sz[ed[j]];
              while (R[i].size() && R[i].back().first == j) ans[R[i].back().second] += qwq, R[i].pop_back();
            }
          }
        }
        dfs2(1);
        for (int i = 1; i <= n; i++) {
          for (auto x : le[i]) {
            int p = ed[x.first];
            while (p ^ 1) {
              ans[x.second] -= bit.qry(dfn[p]);
              p = fa[p];
            }
          }
          bit.add(dfn[ed[i]], 1);
          bit.add(dfn[ed[i]] + sz[ed[i]], -1);
          for (auto x : ri[i]) {
            int p = ed[x.first];
            while (p ^ 1) {
              ans[x.second] += bit.qry(dfn[p]);
              p = fa[p];
            }
          }
        }
      }
      
    } acam;
    
    signed main() {
      n = read(), q = read();
      for (int i = 1; i <= n; i++) {
        scanf("%s", s + 1), len[i] = strlen(s + 1);
        acam.ins(len[i], i);
        tot += len[i];
      }
      acam.build(), S = sqrt(tot);
      for (int i = 1; i <= q; i++) {
        int l = read(), r = read(), k = read();
        if (len[k] > S) {
          L[k].push_back({ l, i });
          R[k].push_back({ r, i });
        } else {
          le[l].push_back({ k, i });
          ri[r].push_back({ k, i });
        }
      }
      acam.solve();
      for (int i = 1; i <= q; i++) printf("%lld
    ", ans[i]);
      return 0;
    }
    
  • 相关阅读:
    10.30NOIP集训总结
    【JZOJ5363】【NOIP2017提高A组模拟9.14】生命之树 Trie+启发式合并
    【JZOJ5338】【NOIP2017提高A组模拟8.25】影子 点分治?/ 排序
    2017.08.13涉猎题集
    【JZOJ5233】【GDOI模拟8.5】概率博弈 树形dp+期望
    【JZOJ5231】【NOIP2017模拟A组模拟8.5】序列问题 线段树
    java8 对List<对象>获取某个属性并去重
    jquery 获取多选select的文本中并拼接成字符串
    idea 配置maven web项目
    如何做PPT
  • 原文地址:https://www.cnblogs.com/Isaunoya/p/12513204.html
Copyright © 2011-2022 走看看