链接:http://acm.hdu.edu.cn/showproblem.php?pid=4641

题意:有一个长度为n(n < 5e4)的字符串,Q(Q<=2e5)次操作;操作分为:在末尾插入一个字符ch和查询不同子串出现次数不小于K的数量;

思路1:SAM在线求解;

对于每次找到将一个字符x插入到SAM之后,我们知道pre[p]所含有的Tx的后缀字符串数目为step[pre[np]]个,那么只需要每次插入之后更新下这些字符串出现的次数cnt即可;

由于Right(fa)与Right(r)没有交集(max(fa) = min(r) - 1),所以需要一直递推到root,但是root不能计算,因为root并没有表示后缀,只是一个init状态;

还有一点就是在拷贝q的信息到nq中时,主要把cnt的信息也拷贝过去;

由于数据较弱。。当出现5e4长度均为a的字符串,2e5次插入操作;这个算法复杂度将达到O(T*n*Q);

(因为每插入一个字符,都需要更新5e4次父节点,这时上面的flag优化没什么卵用。。)

 

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 using namespace std;
 5 
 6 #define maxn 100007
 7 #define SIGMA_SIZE 26
 8 
 9 struct SAM{
10     int sz,tot,last,k;
11     int g[maxn<<1][SIGMA_SIZE],pre[maxn<<1],step[maxn<<1];
12     int vs[maxn<<1],cnt[maxn<<1];
13 
14     void newNode(int s){
15         step[++sz] = s;
16         pre[sz] = 0;
17         vs[sz] = cnt[sz] = 0;
18         memset(g[sz],0,sizeof(g[sz]));
19     }
20 
21     void init(){
22         tot = 0;
23         sz = 0; last = 1;
24         newNode(0);
25     }
26 
27     int idx(char ch){return ch - 'a';}
28 
29     void Insert(char ch){
30         newNode(step[last]+1);
31         int v = idx(ch), p = last, np = sz;
32 
33         while(p && !g[p][v])
34             g[p][v] = np,p = pre[p];    //知道找到Right集合中包含x的边的祖宗节点
35 
36         if(p){
37             int q = g[p][v];
38             if(step[q] == step[p] + 1)
39                 pre[np] = q;
40             else{
41                 newNode(step[p]+1);
42                 int nq = sz;             //nq替换掉q节点
43                 for(int i = 0;i < SIGMA_SIZE;i++)
44                     g[nq][i] = g[q][i];
45 
46                 cnt[nq] = cnt[q];     //**
47                 pre[nq] = pre[q];
48                 pre[np] = pre[q] = nq;
49 
50                 while(p && g[p][v] == q)
51                     g[p][v] = nq,p = pre[p];
52             }
53         }
54         else pre[np] = 1;
55         for(int aux = np;aux != 1 && !vs[aux];aux = pre[aux]){
56             if(++cnt[aux] >= k){
57                 tot += step[aux] - step[pre[aux]];
58                 vs[aux] = true;    //该父节点的子串已经加到tot中
59             }
60         }
61         last = np;
62     }
63 }SA;
64 char str[maxn];
65 int main()
66 {
67     int n,Q;
68     while(scanf("%d%d%d",&n,&Q,&SA.k) == 3){
69         scanf("%s",str);
70         SA.init();
71         int len = strlen(str);
72         for(int i = 0;i < len;i++){
73             SA.Insert(str[i]);
74         }
75         int op;
76         char ch[2];
77         while(Q--){
78             scanf("%d",&op);
79             if(op & 1){
80                 scanf("%s",ch);
81                 SA.Insert(ch[0]);
82             }
83             else printf("%d\n",SA.tot);
84         }
85     }
86 }
View Code

相关文章:

  • 2022-12-23
  • 2021-11-01
  • 2021-08-07
  • 2022-01-24
  • 2021-06-15
  • 2022-01-16
  • 2022-12-23
  • 2021-11-02
猜你喜欢
  • 2021-07-15
  • 2022-12-23
  • 2022-01-15
  • 2022-12-23
  • 2021-08-26
  • 2022-02-15
  • 2022-01-08
相关资源
相似解决方案