题解 基因识别
- 关于「给定一些 \(s\) 和一些 \(t\),每个 \(s\) 向是其子串的 \(t\) 产生贡献」:
注意「\(t\) 是 \(s\) 的子串」还可以被表示为两者拼接后的 \(\tt height\) 数组上的一段区间 \([l, r]\),满足 \(t\) 是区间中每个后缀的前缀
那么就可以转化为区间数颜色问题了
然后本题带修
正解是带修莫队,我也不知道为什么能过
- 注意带修莫队的排序和普通莫队是不同的:以左端点所在块为第一关键字,右端点所在块为第二关键字,时间为第三关键字
复杂度 \(O(n^{\frac{5}{3}})\)
点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 1000010
#define ll long long
#define ull unsigned long long
//#define int long long
int n, m;
ll c[N];
ull h[N], pw[N];
int uni[N], usiz;
string s[N], t[N];
const ull base=13131;
int op[N], x[N], y[N];
inline ull hashing(int l, int r) {return h[r]-h[l-1]*pw[r-l+1];}
// namespace force{
// unordered_map<ull, bool> mp[3002], vis;
// void solve() {
// for (int i=1; i<=m; ++i) if (op[i]==1) {
// ull tem=0;
// for (auto& it:t[i]) tem=tem*base+it;
// vis[tem]=1;
// }
// for (int i=1; i<=n; ++i) {
// for (int j=0; j<s[i].length(); ++j) h[j+1]=h[j]*base+s[i][j];
// for (int j=1; j<=usiz; ++j) {
// int len=uni[j], siz=s[i].length();
// for (int k=1; k+len-1<=siz; ++k) {
// ull tem=hashing(k, k+len-1);
// if (vis.find(tem)!=vis.end()) mp[i][tem]=1;
// }
// }
// }
// for (int i=1; i<=m; ++i) {
// if (op[i]&1) {
// ll ans=0; ull tem=0;
// for (auto& it:t[i]) tem=tem*base+it;
// for (int j=1; j<=n; ++j) if (mp[j].find(tem)!=mp[j].end()) ans+=c[j];
// printf("%lld\n", ans);
// }
// else c[x[i]]+=y[i];
// }
// }
// }
// namespace task1{
// unordered_map<ull, ll> mp;
// unordered_map<ull, bool> now, vis;
// void solve() {
// for (int i=1; i<=m; ++i) if (op[i]==1) {
// ull tem=0;
// for (auto& it:t[i]) tem=tem*base+it;
// vis[tem]=1;
// }
// for (int i=1; i<=n; ++i) {
// now.clear();
// for (int j=0; j<s[i].length(); ++j) h[j+1]=h[j]*base+s[i][j];
// for (int j=1; j<=usiz; ++j) {
// int len=uni[j], siz=s[i].length();
// for (int k=1; k+len-1<=siz; ++k) {
// ull tem=hashing(k, k+len-1);
// if (vis.find(tem)!=vis.end() && now.find(tem)==now.end()) mp[tem]+=c[i], now[tem]=1;
// }
// }
// }
// for (int i=1; i<=m; ++i) {
// if (op[i]&1) {
// ull tem=0;
// for (auto& it:t[i]) tem=tem*base+it;
// printf("%lld\n", mp[tem]);
// }
// else c[x[i]]+=y[i];
// }
// }
// }
namespace task{
char str[N];
ll ans[N], now;
int st[22][N], lg[N], bel[N], sqr;
int pos[N], sa[N], rk[N], id[N], px[N], oldrk[N], cnt[N], ht[N], col[N], k=256, tot, top;
struct que{int l, r, tim, id;}q[N];
// inline bool operator < (que a, que b) {return bel[a.l]==bel[b.l]?(bel[a.l]&1?a.r<b.r:a.r>b.r):bel[a.l]<bel[b.l];}
inline bool operator < (que a, que b) {
if (bel[a.l]^bel[b.l]) return a.l<b.l;
if (bel[a.r]^bel[b.r]) return a.r<b.r;
return a.tim<b.tim;
}
inline bool cmp(int a, int b, int w) {return oldrk[a]==oldrk[b]&&oldrk[a+w]==oldrk[b+w];}
inline int qmin(int l, int r) {
if (l>r) return INF;
int t=lg[r-l+1]-1;
// cout<<"qmin: "<<l<<' '<<r<<' '<<min(st[t][l], st[t][r-(1<<t)+1])<<endl;
return min(st[t][l], st[t][r-(1<<t)+1]);
}
inline void add(int i) {if (++cnt[col[sa[i]]]==1) now+=c[col[sa[i]]];}
inline void del(int i) {if (--cnt[col[sa[i]]]==0) now-=c[col[sa[i]]];}
void solve() {
for (int i=1; i<=n; ++i) {
for (auto& it:s[i]) str[++tot]=it, col[tot]=i;
str[++tot]='#';
}
for (int i=1; i<=m; ++i) if (op[i]&1) {
pos[i]=tot+1;
for (auto& it:t[i]) str[++tot]=it;
str[++tot]='#';
}
// cout<<str+1<<endl;
for (int i=1; i<=tot; ++i) ++cnt[rk[i]=str[i]];
for (int i=1; i<=k; ++i) cnt[i]+=cnt[i-1];
for (int i=1; i<=tot; ++i) sa[cnt[rk[i]]--]=i;
for (int w=1,p; ; w<<=1,k=p) {
p=0;
for (int i=tot; i>tot-w; --i) id[++p]=i;
for (int i=1; i<=tot; ++i) if (sa[i]>w) id[++p]=sa[i]-w;
for (int i=1; i<=k; ++i) cnt[i]=0;
for (int i=1; i<=tot; ++i) ++cnt[px[i]=rk[id[i]]];
for (int i=1; i<=k; ++i) cnt[i]+=cnt[i-1];
for (int i=tot; i; --i) sa[cnt[px[i]]--]=id[i];
for (int i=1; i<=tot; ++i) oldrk[i]=rk[i];
p=0;
for (int i=1; i<=tot; ++i) rk[sa[i]]=cmp(sa[i], sa[i-1], w)?p:++p;
if (p==tot) break;
}
for (int i=1,k=0; i<=tot; ++i) {
if (k) --k;
while (str[i+k]==str[sa[rk[i]-1]+k]) ++k;
ht[rk[i]]=k;
}
// cout<<"---sa---"<<endl; for (int i=1; i<=tot; ++i) {cout<<setw(2)<<i<<" h("<<setw(1)<<col[sa[i]]<<"): "; for (int j=sa[i]; j<=tot; ++j) cout<<str[j]; cout<<endl;}
for (int i=1; i<=tot; ++i) lg[i]=lg[i-1]+(1<<lg[i-1]==i);
for (int i=1; i<=tot; ++i) st[0][i]=ht[i];
int t=lg[tot]-1;
for (int i=1; i<=t; ++i)
for (int j=1; j+(1<<i)-1<=tot; ++j)
st[i][j]=min(st[i-1][j], st[i-1][j+(1<<i-1)]);
for (int i=1; i<=m; ++i) if (op[i]&1) {
// cout<<"i: "<<i<<endl;
int l, r, tl, tr, mid;
// cout<<"pos: "<<rk[pos[i]]<<endl;
tl=1, tr=rk[pos[i]];
while (tl<=tr) {
mid=(tl+tr)>>1;
if (qmin(mid+1, rk[pos[i]])>=::t[i].length()) tr=mid-1;
else tl=mid+1;
}
l=tr+1;
tl=rk[pos[i]], tr=tot;
while (tl<=tr) {
mid=(tl+tr)>>1;
if (qmin(rk[pos[i]]+1, mid)>=::t[i].length()) tl=mid+1;
else tr=mid-1;
}
r=tl-1;
// cout<<"t: "<<::t[i]<<endl;
// cout<<"lr: "<<l<<' '<<r<<endl;
++top, q[top]={l, r, i, top};
}
// cout<<"top: "<<top<<endl;
sqr=pow(m, 0.666);
for (int i=1; i<=tot; ++i) bel[i]=(i-1)/sqr+1;
sort(q+1, q+top+1);
memset(cnt, 0, sizeof(cnt));
for (int i=1,l=0,r=0,k=0; i<=top; ++i) {
while (l>q[i].l) add(--l);
while (r<q[i].r) add(++r);
while (l<q[i].l) del(l++);
while (r>q[i].r) del(r--);
while (k<q[i].tim) if (!(op[++k]&1)) {
if (cnt[x[k]]) now+=y[k];
c[x[k]]+=y[k];
}
while (k>q[i].tim) if (!(op[k--]&1)) {
if (cnt[x[k+1]]) now-=y[k+1];
c[x[k+1]]-=y[k+1];
}
ans[q[i].id]=now;
}
for (int i=1; i<=top; ++i) printf("%lld\n", ans[i]);
}
}
signed main()
{
freopen("dna.in", "r", stdin);
freopen("dna.out", "w", stdout);
ios::sync_with_stdio(0);
cin>>n>>m;
for (int i=1; i<=n; ++i) cin>>c[i]>>s[i];
for (int i=1; i<=m; ++i) {
cin>>op[i];
if (op[i]&1) cin>>t[i], uni[++usiz]=t[i].length();
else cin>>x[i]>>y[i];
}
sort(uni+1, uni+usiz+1);
usiz=unique(uni+1, uni+usiz+1)-uni-1;
pw[0]=1;
for (int i=1; i<N; ++i) pw[i]=pw[i-1]*base;
// if (n<=3000) force::solve();
// else task1::solve();
task::solve();
return 0;
}