Mike and Friends[CF547E]

链接

CF

题解

练手速的题

这种题也需要写20min。。。

显然你建一个广义SAM然后离线一下再线段树合并就没了。

时间复杂度 $O(n\log n)$。

注意广义SAM不仅需要las=1,还需要特殊处理一些东西。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#include <bits/stdc++.h>
using namespace std;
#define FO(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
#define fo(i,j,k) for(int i=(j),end_i=(k);i<=end_i;i++)
#define ff(i,j,k) for(int i=(j),end_i=(k);i< end_i;i++)
#define fd(i,j,k) for(int i=(j),end_i=(k);i>=end_i;i--)
#define DEBUG(x) cerr<<#x<<"="<<x<<endl
#define all(x) (x).begin(),(x).end()
#define cle(x) memset(x,0,sizeof(x))
#define lowbit(x) ((x)&-(x))
#define ll long long
#define ull unsigned ll
#define db double
#define lb long db
#define pb push_back
#define mp make_pair
#define fi first
#define se second
inline int read()
{
int x=0; char ch=getchar(); bool f=0;
for(;ch<'0'||ch>'9';ch=getchar()) if(ch=='-') f=1;
for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<3)+(x<<1)+(ch^48);
return f?-x:x;
}
#define CASET fo(___,1,read())
const int N=400010;
const int M=N*20;
int n,m;
int ans[N*2];
struct query{
int x,y,id;
};
int ls[M],rs[M],cnt;
int siz[M];
void update(int &u,int l,int r,int p)
{
if(!u) u=++cnt;
siz[u]++;
if(l==r) return;
int mid=l+r>>1;
(p<=mid)?update(ls[u],l,mid,p):update(rs[u],mid+1,r,p);
}
int merge(int x,int y)
{
if(!x||!y) return x+y;
ls[x]=merge(ls[x],ls[y]);
rs[x]=merge(rs[x],rs[y]);
siz[x]+=siz[y];
return x;
}
int ask(int u,int l,int r,int L,int R)
{
if(!u) return 0;
if(L<=l&&r<=R) return siz[u];
int mid=l+r>>1; int ans=0;
if(L<=mid) ans+=ask(ls[u],l,mid,L,R);
if(mid<R) ans+=ask(rs[u],mid+1,r,L,R);
return ans;
}
int rt[N],pos[N];
namespace Tree{
vector<int> adj[N];
vector<query> vec[N];
inline void add(int x,int y){adj[x].pb(y);}
void dfs(int u)
{
for(auto v:adj[u]) dfs(v),rt[u]=merge(rt[u],rt[v]);
for(auto v:vec[u]) ans[v.id]=ask(rt[u],1,n,v.x,v.y);
}
}

namespace SAM{
int ne[N<<1][26],fa[N<<1],len[N<<1],cnt,las;
void init() {cnt=las=1;}
inline void extend(int c)
{
if(ne[las][c])
{
int p=las,q=ne[p][c];
if(len[q]==len[p]+1) {las=q; return;}
int clone=++cnt;
memcpy(ne[clone],ne[q],sizeof(ne[q]));
len[clone]=len[p]+1;
fa[clone]=fa[q];
for(;p&&ne[p][c]==q;p=fa[p]) ne[p][c]=clone;
fa[q]=clone;
las=clone;
return;
}
int cur=++cnt,p=las;
len[cur]=len[p]+1;
for(;p&&!ne[p][c];p=fa[p]) ne[p][c]=cur;
if(!p) fa[cur]=1;
else
{
int q=ne[p][c];
if(len[q]==len[p]+1) fa[cur]=q;
else
{
int clone=++cnt;
memcpy(ne[clone],ne[q],sizeof(ne[q]));
len[clone]=len[p]+1;
fa[clone]=fa[q];
for(;p&&ne[p][c]==q;p=fa[p]) ne[p][c]=clone;
fa[q]=fa[cur]=clone;
}
}
las=cur;
}
void build()
{
fo(i,2,cnt) Tree::add(fa[i],i);
}
}
using SAM::las;
char s[N];
int main()
{
n=read(); m=read();
SAM::init();
fo(i,1,n)
{
las=1;
scanf("%s",s+1);
int len=strlen(s+1);
fo(j,1,len) SAM::extend(s[j]-'a'),update(rt[las],1,n,i);
pos[i]=las;
}
SAM::build();
int x,y,z;
fo(i,1,m)
{
x=read(),y=read(),z=pos[read()];
Tree::vec[z].pb((query){x,y,i});
}
Tree::dfs(1);
fo(i,1,m) printf("%d\n",ans[i]);
return 0;
}