HDU 4641 K-string 后缀自动机 并查集

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

https://blog.csdn.net/asdfgh0308/article/details/40969047

给一个小写字母字符串,1 a表示在字符串尾部添加一个小写字母a,2 表示当前有多少种子串出现次数大于等于K。

求出现次数桶排序(说是拓扑排序也可以?)就阔以了,种类就是t[i].len-t[t[i].f].len。

在线处理是直接扫描,时间复杂度是O(树高*m)。

离线做法是先把所有添加操作都做完,然后去掉字母反向求子串种数,可以使用并查集降低时间复杂度(每个连通块中只有总父亲表示的子串对当前答案有贡献,保证了每个点的平均扫描次数)。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<cmath>
 6 #include<queue>
 7 using namespace std;
 8 #define LL long long
 9 const int maxn=60100;
10 int n,m,K;
11 char ch[maxn*10],ch1[3];
12 int e[maxn*4]={},b[maxn*5]={},siz;
13 struct nod{
14     int sig[26],f,len;
15 }t[maxn*10]; int tot,la;
16
17 int cnt[maxn*10]={},rk[maxn*10]={};
18 int fa[maxn*10]={},sub[maxn*10]={},g[maxn*10]={};
19 LL ans[maxn*4]={};
20
21 void addit(int z){
22     int x=++tot,i=la; t[x].len=t[i].len+1;
23     b[siz]=x;
24     for(;i&&!t[i].sig[z];i=t[i].f)t[i].sig[z]=x;
25     if(!i)t[x].f=1;
26     else{
27         int y=t[i].sig[z];
28         if(t[y].len==t[i].len+1)t[x].f=y;
29         else{
30             int p=++tot;
31             t[p]=t[y];t[p].len=t[i].len+1;
32             t[y].f=t[x].f=p;
33             for(;i&&t[i].sig[z]==y;i=t[i].f)t[i].sig[z]=p;
34         }
35     }
36     la=x;
37 }
38 void msort(){
39     int i;
40     for(i=0;i<=siz;i++)cnt[i]=0;
41     for(i=2;i<=tot;i++)cnt[t[i].len]++;
42     for(i=1;i<=siz;i++)cnt[i]+=cnt[i-1];
43     for(i=tot;i>1;i--)rk[cnt[t[i].len]--]=i;
44 }
45 int getfa(int x){
46     int y=x,z;
47     while(y!=fa[y])y=fa[y];
48     while(x!=fa[x]){ z=x; x=fa[x];fa[z]=y;}
49     return fa[x];
50 }
51 int main(){
52     int i,p,y; LL num;
53     while(~scanf("%d%d%d",&n,&m,&K)){
54         memset(t,0,sizeof(t)); tot=1; la=1; siz=0;
55         scanf("%s",ch);
56         for(i=0;i<n;++i){ addit(ch[i]-‘a‘); ++siz; }
57         for(i=1;i<=m;i++){
58             scanf("%d",&e[i]);
59             if(e[i]==1){ scanf("%s",ch1); addit(ch1[0]-‘a‘); ch[siz++]=ch1[0]; }
60         }
61         msort(); p=1,num=0;
62         for(i=1;i<=tot;i++){ g[i]=0; fa[i]=i; sub[i]=0;}
63         for(i=0;i<siz;++i){ p=t[p].sig[ch[i]-‘a‘]; ++g[p]; }
64         for(i=tot-1;i>0;i--){ p=rk[i]; if(t[p].f!=1)g[t[p].f]+=g[p]; }
65         for(i=2;i<=tot;++i){ if(g[i]>=K) num+=t[i].len-t[t[i].f].len; }
66         for(i=m;i>0;i--){
67             if(e[i]==2)ans[i]=num;
68             else{
69                 p=b[--siz];
70                 y=getfa(p);
71                 while(y!=1&&g[y]<K){ fa[y]=getfa(t[y].f); y=fa[y];}
72                 y=getfa(p);
73                 if(y==1)continue;
74                 sub[y]++;
75                 while(y!=1&&(g[y]-sub[y]<K)){
76                     num-=t[y].len-t[t[y].f].len;
77                     p=getfa(t[y].f);
78                     sub[p]+=sub[y]; fa[y]=p;
79                     y=fa[y];
80                 }
81             }
82         }
83         for(i=1;i<=m;++i)if(e[i]==2)printf("%lld\n",ans[i]);
84     }
85     return 0;
86 }

原文地址:https://www.cnblogs.com/137shoebills/p/8968931.html

时间: 2024-10-15 06:19:24

HDU 4641 K-string 后缀自动机 并查集的相关文章

hdu 1272 小希的迷宫(简单并查集)

小希的迷宫 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 31396    Accepted Submission(s): 9726 Problem Description 上次Gardon的迷宫城堡小希玩了很久(见Problem B),现在她也想设计一个迷宫让Gardon来走.但是她设计迷宫的思路不一样,首先她认为所有的通道都应该是

hdu 1829 A Bug&#39;s Life 并查集系列

1 #include "cstdio" 2 #include "iostream" 3 #include "cstring" 4 #include "vector" 5 #include "queue" 6 using namespace std; 7 8 #define MAXN 2222 9 int fa[MAXN]; 10 int rnk[MAXN]; //秩 表示某点与根的距离 11 int n,

HDU 1232:畅通问题(并查集)

畅通工程 Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 29362    Accepted Submission(s): 15452 Problem Description 某省调查城镇交通状况,得到现有城镇道路统计表,表中列出了每条道路直接连通的城镇.省政府"畅通工程"的目标是使全省任何两个城镇间都可以实现交通(但不一定有

HDU 3081Marriage Match II(二分+并查集+网络流之最大流)

题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=3081 有一段时间没写最大流的题了,这题建图居然想了好长时间...刚开始是按着最终的最大流即是做多轮数去想建图,结果根本没思路,后来想了想,可以用二分答案的思想来找最终答案.然后很明显的并查集,但是并查集学的略渣,居然卡在并查集上了..= =. 但是也不是并查集的事..是我建图的思想太正了,稍微用点逆向思维并查集就可以很好利用了. 建图思路是:建立一个源点与汇点,将女孩与源点相连,男孩与汇点相连,权值

hdu 5458 Stability(树链剖分+并查集)

Stability Time Limit: 3000/2000 MS (Java/Others)    Memory Limit: 65535/102400 K (Java/Others)Total Submission(s): 1347    Accepted Submission(s): 319 Problem Description Given an undirected connected graph G with n nodes and m edges, with possibly r

HDU 1988 Cube Stacking (数据结构-并查集)

Cube Stacking Time Limit: 2000MS   Memory Limit: 30000K Total Submissions: 18900   Accepted: 6568 Case Time Limit: 1000MS Description Farmer John and Betsy are playing a game with N (1 <= N <= 30,000)identical cubes labeled 1 through N. They start w

hdu 4496 D-City (逆向思维的并查集)

D-City Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)Total Submission(s): 1388    Accepted Submission(s): 520 Problem Description Luxer is a really bad guy. He destroys everything he met. One day Luxer went to D-c

HDU 1325 Is It A Tree? 并查集

判断是否为树 森林不是树 空树也是树 成环不是树 数据: 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 1 0 0 1 2 2 3 4 5 0 0 2 5 0 0 ans: no no yes #include <stdio.h> #include <string.h> #include <stdlib.h> #include <limits.h> #include <malloc.h> #include <ctype

HDU 4879 ZCC loves march(并查集+set)

题意:一个最大10^18*10^18的矩阵,给你最多十万个士兵的位置,分别分布在矩阵里,可能会位置重复,然后有2种操作,一种是把第i个士兵向上下左右移动,另一种是把第i个士兵与他横坐标纵坐标相同的士兵全部移到这个点上,然后要计算花费. 这道题我想了好几天.在看了标程得到一些提示后总算写出来了.加了读入优化后快了100ms左右达到546ms. 做法:开2个set分别维护X相同的和Y相同的,但是会有相同位置点的坐标,该怎么办?用并查集去维护相同位置的点,读入的时候就可能会有位置相同的点,所以读的时候