P5840 题解
_sunkuangzheng_ · · 题解
AC 自动机太 hard 了,提供一个无脑 SA 做法。
考虑问题的弱化版本:所有查询在修改之后。我们把所有
考虑一边插入一边查询,相当于增加了时间维度。离线所有操作,做和上面一样的操作,只不过查询变成了
采用
但是你 TLE 啦!经过测试发现跑完 SA 就已经 TLE 了。复制 atcoder 头文件里线性 SA 就好了,可以 AC。
/**
* author: sunkuangzheng
* created: 04.01.2024 11:00:42
**/
#include<bits/stdc++.h>
// #ifdef DEBUG_LOCAL
// #include <mydebug/debug.h>
// debug_helper deg;
// #endif
using ll = long long;
const int N = 4e6+3e5+5;
using namespace std;string s,t;vector<tuple<int,int,int>> qq;
int T,n,al[N],ar[N],q,op,p,m,sa[N],ok[N],rk[N],h[N],st[N][25],len[N],lst[N],mp[N],tr[N],re;
namespace atcoder {
//篇幅原因省略这一部分,见 https://atcoder.github.io/ac-library/production/document_en/string.html
}using namespace atcoder;
void upd(int x,int p){for(;x <= n;x += x & -x) tr[x] += p;}
int qry(int x){for(re = 0;x;x -= x & -x) re += tr[x];return re;}
struct fk{int a,b,c,id;}a[N*3];
struct count{
int cnt,ans[N];
void add(int x,int y,int z,int id){a[++cnt] = {x,y,z,id};}
void cdq(int l,int r){
if(l == r) return ;
int mid = (l + r) / 2,i = mid + 1,j = l;
auto cmp = [&](fk a,fk b){return a.b < b.b || a.b == b.b && a.c < b.c;};
cdq(l,mid),cdq(mid+1,r);
sort(a+l,a+mid+1,cmp),sort(a+mid+1,a+r+1,cmp);
for(;i <= r;i ++){
for(;a[i].b >= a[j].b && j <= mid;j ++) if(!a[j].id) upd(a[j].c,1);
if(a[i].id != 0) ans[abs(a[i].id)] += (a[i].id > 0 ? 1 : -1) * qry(a[i].c);
}for(int k = l;k < j;k ++) if(!a[k].id) upd(a[k].c,-1);
}void sol(int n){for(int i = 1;i <= n;i ++) ans[i] = 0;cnt = 0;}
}hh;
void SA(string &s,int &n){
n = s.size();
vector<int> _sa = suffix_array(s);s = " " + s;
for(int i = 1;i <= n;i ++) sa[i] = _sa[i-1]+1,rk[sa[i]] = i;
}void grgh(int n){
for(int i = 1,k = 0;i <= n;h[rk[i ++]] = k)
for(k --,k = max(k,0);s[i + k] != '#' && s[i + k] == s[sa[rk[i] - 1] + k];k ++);
for(int i = 1;i <= n;i ++) st[i][0] = h[i];
for(int j = 1;j <= __lg(n);j ++) for(int i = 1;i + (1 << j) - 1 <= n;i ++)
st[i][j] = min(st[i][j-1],st[i+(1<<j-1)][j-1]);
}void los(){
cin >> n;
for(int i = 1;i <= n;i ++) cin >> t,al[i] = s.size() + 1,s += t + '#',ar[i] = s.size() - 1,len[i] = t.size();
cin >> q;int ed = n;
for(int i = 1;i <= q;i ++){
cin >> op;
if(op == 1) cin >> t,al[++n] = s.size() + 1,s += t + '#',ar[n] = s.size() - 1;
else cin >> p,qq.emplace_back(p,n,i);
}SA(s,m),grgh(m);
auto lcp = [&](int i,int j){
if(i == j) return m - sa[i] + 1;
int k = __lg(j - i);
return min(st[i+1][k],st[j-(1<<k)+1][k]);
};hh.sol(q);
for(auto [k,id,di] : qq){
int l,r,ql,qr,le = len[k]; k = rk[al[k]];
for(l = 1,r = k;l <= r;){
int mid = (l + r) / 2;
if(lcp(mid,k) >= le) r = mid - 1; else l = mid + 1;
}ql = r + 1;
for(l = k,r = m;l <= r;){
int mid = (l + r) / 2;
if(lcp(k,mid) >= le) l = mid + 1; else r = mid - 1;
}qr = l - 1;
hh.add(ql-1,ql-1,id,-di),hh.add(qr,ql-1,id,di);
}for(int i = 1;i <= n;i ++) for(int j = al[i];j <= ar[i];j ++) mp[rk[j]] = i;
for(int i = 1;i <= m;i ++){
if(mp[i] <= ed) continue;
hh.add(i,lst[mp[i]],mp[i],0),lst[mp[i]] = i;
}//cout << hh.cnt << "\n";
sort(a+1,a+hh.cnt+1,[&](fk a,fk b){return a.a < b.a || a.a == b.a && a.b < b.b || a.a == b.a && a.b == b.b && a.c < b.c;});
hh.cdq(1,hh.cnt);
for(auto [k,id,di] : qq) cout << hh.ans[di] << "\n";
}int main(){
ios::sync_with_stdio(0),cin.tie(0);
for(T = 1;T --;) los();
}