• CF666E. Forensic Examination


    题意:

    给你一个串S以及一个字符串数组T[1..m]q次询问,每次问S的子串S[pl..pr]在T[l..r]中的哪个串里的出现次数最多,并输出出现次数。

    如有多解输出最靠前的那一个。

    解:

    什么奇葩排版......

    对T建广义SAM,线段树合并维护每个节点有哪些串。写法稍微注意一下。

    记录下s在t上匹配的时候每个前缀走到哪个位置。然后树上倍增找到符合条件的节点,线段树上查询。

    如果查到0或者根本没那么长的匹配长度,输出"L 0"

      1 #include <iostream>
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <string>
      5 #include <algorithm>
      6 
      7 const int N = 500010, M = 20000010;
      8 
      9 struct Edge {
     10     int nex, v;
     11 }edge[N * 2]; int tp;
     12 
     13 char str[N];
     14 int tr[N * 2][26], len[N * 2], fail[N * 2], tot = 1, n, m, L, R, e[N * 2], cnt;
     15 std::string ss[N];
     16 int large[M], ans[M], rt[N * 2], ls[M], rs[M], pos[N], lenth[N], fa[N * 2][20], pw[N * 2];
     17 
     18 inline void add(int x, int y) {
     19     tp++;
     20     edge[tp].v = y;
     21     edge[tp].nex = e[x];
     22     e[x] = tp;
     23     return;
     24 }
     25 
     26 inline void Max(int &a, int b) {
     27     if(!b) return;
     28     if(large[b] > large[a] || (large[b] == large[a] && ans[a] > ans[b])) {
     29         a = b;
     30     }
     31     return;
     32 }
     33 
     34 inline void pushup(int o) {
     35     large[o] = std::max(large[ls[o]], large[rs[o]]);
     36     if(large[ls[o]] > large[rs[o]]) {
     37         ans[o] = ans[ls[o]];
     38     }
     39     else if(large[rs[o]] > large[ls[o]]) {
     40         ans[o] = ans[rs[o]];
     41     }
     42     else ans[o] = std::min(ans[ls[o]], ans[rs[o]]);
     43     return;
     44 }
     45 
     46 inline void insert(int p, int l, int r, int &o) {
     47     if(!o) o = ++cnt;
     48     if(l == r) {
     49         ans[o] = r;
     50         large[o]++;
     51         return;
     52     }
     53     int mid = (l + r) >> 1;
     54     if(p <= mid) insert(p, l, mid, ls[o]);
     55     else insert(p, mid + 1, r, rs[o]);
     56     pushup(o);
     57     return;
     58 }
     59 
     60 inline int merge(int x, int y, int l, int r) {
     61     if(!x || !y) return x | y;
     62     if(l == r) {
     63         int o = ++cnt;
     64         large[o] = large[x] + large[y];
     65         ans[o] = r;
     66         return o;
     67     }
     68     int o = ++cnt, mid = (l + r) >> 1;
     69     ls[o] = merge(ls[x], ls[y], l, mid);
     70     rs[o] = merge(rs[x], rs[y], mid + 1, r);
     71     pushup(o);
     72     return o;
     73 }
     74 
     75 void out(int l, int r, int x) {
     76     if(!x) printf("!x");
     77     printf("(%d [%d %d] lar=%d ans=%d) ", x, l, r, large[x], ans[x]);
     78     if(l == r) {
     79         printf("%d ", r);
     80         return;
     81     }
     82     int mid = (l + r) >> 1;
     83     if(ls[x]) out(l, mid, ls[x]);
     84     if(rs[x]) out(mid + 1, r, rs[x]);
     85     return;
     86 }
     87 
     88 void DFS(int x) {
     89     for(int i = e[x]; i; i = edge[i].nex) {
     90         int y = edge[i].v;
     91         DFS(y);
     92         rt[x] = merge(rt[x], rt[y], 1, m);
     93     }
     94     return;
     95 }
     96 
     97 inline int ask(int l, int r, int o) { /// return a Node
     98     if(!o) return 0;
     99     if(L <= l && r <= R) return o;
    100     int mid = (l + r) >> 1, Ans = 0;
    101     if(L <= mid) Max(Ans, ask(l, mid, ls[o]));
    102     if(mid < R) Max(Ans, ask(mid + 1, r, rs[o]));
    103     return Ans;
    104 }
    105 
    106 inline int split(int p, int f) {
    107     int Q = tr[p][f], nQ = ++tot;
    108     len[nQ] = len[p] + 1;
    109     fail[nQ] = fail[Q];
    110     fail[Q] = nQ;
    111     memcpy(tr[nQ], tr[Q], sizeof(tr[Q]));
    112     while(tr[p][f] == Q) {
    113         tr[p][f] = nQ;
    114         p = fail[p];
    115     }
    116     return nQ;
    117 }
    118 
    119 inline int insert(char c, int p, int id) {
    120     int f = c - 'a', np;
    121     if(tr[p][f]) {
    122         int Q = tr[p][f];
    123         if(len[Q] == len[p] + 1) {
    124             np = Q;
    125         }
    126         else np = split(p, f);
    127         insert(id, 1, m, rt[np]);
    128         return np;
    129     }
    130     np = ++tot;
    131     len[np] = len[p] + 1;
    132     while(p && !tr[p][f]) {
    133         tr[p][f] = np;
    134         p = fail[p];
    135     }
    136     if(!p) {
    137         fail[np] = 1;
    138     }
    139     else {
    140         int Q = tr[p][f];
    141         if(len[Q] == len[p] + 1) {
    142             fail[np] = Q;
    143         }
    144         else {
    145             fail[np] = split(p, f);
    146         }
    147     }
    148     insert(id, 1, m, rt[np]);
    149     return np;
    150 }
    151 
    152 inline int getpos(int l, int r) {
    153     int p = pos[r], Len = r - l + 1;
    154     if(lenth[r] < Len) return 0;
    155     int t = pw[tot];
    156     while(t >= 0) {
    157         if(len[fa[p][t]] >= Len) {
    158             p = fa[p][t];
    159         }
    160         t--;
    161     }
    162     return p;
    163 }
    164 
    165 int main() {
    166     scanf("%s", str + 1);
    167     n = strlen(str + 1);
    168     scanf("%d", &m);
    169     for(int i = 1; i <= m; i++) {
    170         std::cin >> ss[i];
    171         int k = ss[i].size(), p = 1;
    172         for(int j = 0; j < k; j++) {
    173             p = insert(ss[i][j], p, i);
    174         }
    175     }
    176     /// insert OVER
    177     for(int i = 2; i <= tot; i++) {
    178         add(fail[i], i);
    179         fa[i][0] = fail[i];
    180     }
    181     DFS(1);
    182     for(int i = 2; i <= tot; i++) pw[i] = pw[i >> 1] + 1;
    183     for(int j = 1; j <= pw[tot]; j++) {
    184         for(int i = 1; i <= tot; i++) {
    185             fa[i][j] = fa[fa[i][j - 1]][j - 1];
    186         }
    187     }
    188     int Len = 0, p = 1;
    189     for(int i = 1; i <= n; i++) {
    190         int ff = str[i] - 'a';
    191         while(p && !tr[p][ff]) {
    192             p = fail[p];
    193             Len = len[p];
    194         }
    195         if(!p) {
    196             p = 1;
    197         }
    198         else {
    199             p = tr[p][ff];
    200             Len++;
    201         }
    202         pos[i] = p;
    203         lenth[i] = Len;
    204     }
    205     /// prework OVER
    206     int q, l, r;
    207     scanf("%d", &q);
    208     for(int i = 1; i <= q; i++) {
    209         scanf("%d%d%d%d", &L, &R, &l, &r);
    210         p = getpos(l, r);
    211         if(!p) printf("%d 0
    ", L);
    212         else {
    213             int Ans = ask(1, m, rt[p]);
    214             if(!Ans) printf("%d 0
    ", L);
    215             else printf("%d %d
    ", ans[Ans], large[Ans]);
    216         }
    217     }
    218     return 0;
    219 }
    AC代码

    我调了一晚上差点气疯了,结果是因为tr数组第二维只开了2...这个数组脱离我的控制...

  • 相关阅读:
    c# 把对象加入队列,对象为全局变量,对象改变队列值也跟着改变
    C# 一个数组未赋值引发的错误
    c# 2016QQ自动登录程序
    当时钟事件声明为过程变量 让system.threading.timer时钟失效
    if 循环的深入理解 哈希表的一种应用
    VB6对象与地址相互转换
    VB6的函数指针传递
    .net framework 4.0 从 GAC 卸载 程序集
    .net framework 4.0 从 GAC 卸载 程序集
    GAC in CLR 3.0
  • 原文地址:https://www.cnblogs.com/huyufeifei/p/10479589.html
Copyright © 2020-2023  润新知