P4770(SAM+主席树+倍增)

题意:

给定一个母串,$q$次查询每个串的本质不同子串在原串对应的$[l,r]$子串中不出现的个数

题解:

感觉非常坑人的是

并没有从题目中看出 需要满足查询串的本质不同的情况

那么对于不用考虑查询串的本质不同的话 那么就直接 对于每个询问串在原串的sam上跑一遍 通过倍增统计答案即可

现在需要求本质不同的情况 那么我们考虑 预处理以每个节点为结尾的前缀 最短需要多长是满足题意

然后对于查询串建sam 然后综合预处理 对于每个节点统计答案

复杂度 $O(T*20log(n))$

代码实现:

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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <stack>
#include <queue>
#include <cmath>
#include <set>
#include <map>
#define mp make_pair
#define pb push_back
#define pii pair<int,int>
#define link(x) for(edge *j=h[x];j;j=j->next)
#define inc(i,l,r) for(int i=l;i<=r;i++)
#define dec(i,r,l) for(int i=r;i>=l;i--)
const int MAXN=3e6+10;
const double eps=1e-8;
const int mod=1e9+9;
#define ll long long
using namespace std;
struct edge{int t;edge*next;}e[MAXN<<1],*h[MAXN],*o=e;
void add(int x,int y){o->t=y;o->next=h[x];h[x]=o++;}
ll read(){
ll x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return x*f;
}


int dis[MAXN],fa[MAXN],ch[MAXN][26],n;
char str[MAXN];
int Rt[MAXN],f[MAXN][21];
int rt,cnt,cur,num;
typedef struct npde{
int l,r,sum;
}node;
node d[MAXN*21];
void update(int &x,int l,int r,int t){
if(!x)x=++num;
d[x].sum++;
if(l==r)return ;
int mid=(l+r)>>1;
if(t<=mid)update(d[x].l,l,mid,t);
else update(d[x].r,mid+1,r,t);
}
void merge(int &x,int y,int l,int r){
if(!y)return ;
if(!x){x=y;return ;}
int t=++num;d[t]=d[x];d[t].sum+=d[y].sum;x=t;
if(l==r)return ;
int mid=(l+r)>>1;
merge(d[x].l,d[y].l,l,mid);
merge(d[x].r,d[y].r,mid+1,r);
d[x].sum=d[d[x].l].sum+d[d[x].r].sum;
}
void built(int x){
int last=cur;cur=++cnt;dis[cur]=dis[last]+1;int p=last;
update(Rt[cur],1,n,dis[cur]);
for(;p&&!ch[p][x];p=fa[p])ch[p][x]=cur;
if(!p)fa[cur]=rt;
else{
int q=ch[p][x];
if(dis[q]==dis[p]+1)fa[cur]=q;
else{
int nt=++cnt;dis[nt]=dis[p]+1;
memcpy(ch[nt],ch[q],sizeof(ch[q]));
fa[nt]=fa[q];fa[q]=fa[cur]=nt;
for(;ch[p][x]==q;p=fa[p])ch[p][x]=nt;
}
}
}
void dfs(int x){
inc(i,1,20)f[x][i]=f[f[x][i-1]][i-1];
link(x){
dfs(j->t);
merge(Rt[x],Rt[j->t],1,n);
}
}
int ans1;
void querty(int x,int l,int r,int ql,int qr){
if(ql<=l&&r<=qr){
ans1+=d[x].sum;return ;
}
int mid=(l+r)>>1;
if(ql<=mid)querty(d[x].l,l,mid,ql,qr);
if(qr>mid)querty(d[x].r,mid+1,r,ql,qr);
}
int L,R;
bool check(int x,int y){
if(!x)return 1;
ans1=0;querty(Rt[x],1,n,L+y-1,R);
if(ans1>0)return 1;
return 0;
}
char s[MAXN];
int Sum[MAXN];
int dis1[MAXN],fa1[MAXN],ch1[MAXN][26];
int rt1,cnt1,cur1,maxx[MAXN];
void built1(int x){
int last=cur1;cur1=++cnt1;dis1[cur1]=dis1[last]+1;int p=last;
maxx[cur1]=dis1[cur1];
for(;p&&!ch1[p][x];p=fa1[p])ch1[p][x]=cur1;
if(!p)fa1[cur1]=rt1;
else{
int q=ch1[p][x];
if(dis1[q]==dis1[p]+1)fa1[cur1]=q;
else{
int nt=++cnt1;dis1[nt]=dis1[p]+1;
memcpy(ch1[nt],ch1[q],sizeof(ch1[q]));
fa1[nt]=fa1[q];fa1[q]=fa1[cur1]=nt;
for(;ch1[p][x]==q;p=fa1[p])ch1[p][x]=nt;
}
}
}
vector<int>vec[MAXN];
void _dfs(int x){
for(int i=0;i<vec[x].size();i++){
_dfs(vec[x][i]);
maxx[x]=maxx[vec[x][i]];
}
}
int main(){
scanf("%s",str+1);int len=strlen(str+1);n=len;
rt=cnt=cur=1;
inc(i,1,len)built(str[i]-'a');
inc(i,1,cnt)add(fa[i],i),f[i][0]=fa[i];
dfs(rt);
int q=read();
while(q--){
scanf("%s",s+1);L=read();R=read();
len=strlen(s+1);int temp=rt;int ans=0;
inc(i,1,len){
int t=s[i]-'a';
if(ch[temp][t])temp=ch[temp][t],ans++;
else{
int p=temp;
for(;p&&!ch[p][t];p=fa[p]);
if(!p)temp=rt,ans=0;else temp=ch[p][t],ans=dis[p]+1;
}
int x=temp;int y=ans;
dec(j,20,0){
if(!check(f[x][j],dis[f[x][j]]))x=f[x][j],y=dis[x];
}
int l=dis[fa[x]]+1;int r=y;int ans2=dis[fa[x]];
while(l<=r){
int mid=(l+r)>>1;
if(check(x,mid))ans2=mid,l=mid+1;
else r=mid-1;
}
Sum[i]=ans2+1;
}
cnt1=cur1=rt1=1;
inc(i,1,len)built1(s[i]-'a');
inc(i,1,cnt1)vec[fa1[i]].pb(i);
_dfs(rt1);
ll sum=0;
inc(i,1,cnt1){
int t=max(Sum[maxx[i]],dis1[fa1[i]]+1);
sum+=max(0,dis1[i]-t+1);
vec[i].clear();
}
inc(i,1,cnt1)memset(ch1[i],0,sizeof(ch1[i])),dis1[i]=maxx[i]=fa1[i]=0;
printf("%lld\n",sum);
}
return 0;
}