题解:P14363 [CSP-S 2025] 谐音替换 / replace(暂无数据)
[CSP-S 2025] T3 谐音替换 题解
先特判掉
然后对于每个输入的
那么显然有
其中
然后,因为
对于每一个
然后对 Trie 树求出 dfs 序,设点
至此就是二维矩形加、单点查询了,使用二维差分容易转化为单点加、二维矩形查询,扫描线+树状数组即可。
时间复杂度
::::warning[注意事项]
不要使用 map<string,int>,哈希不要模 1e9 级别模数。内存都给 2GB 了应该不会爆吧。
查询串在 Trie 树上往下跳的时候,如果当前节点不存在对应字母的子节点,则代表查询串只有这个前缀是有效的,后面都匹配不上了,务必立即 return。否则如果后面再出现有子节点的字母,则还会继续跳,这个时候跳出来的就不是前缀了,然后就WA了,
::::success[代码]
#include<bits/stdc++.h>
#define ll long long
#define ld long double
#define fi first
#define se second
#define pb push_back
#define pii pair<int,int>
#define ve vector<int>
#define mid (l+r>>1)
#define lx (x<<1)
#define rx (x<<1|1)
using namespace std;
const int N=1e6+2,M=6e6+2;
const ll P=1e16+61;
int n,m,k,d,ck,cnt,tr[M],dfn[M],ans[N],dfm[M],rt[N],f[M][26];
pii c[N];
struct node{int x,y,z,t;}mf[N];
map<ll,int>mp;
void mdf(int x,int y){for(;x<=k;x+=x&-x)tr[x]+=y;}
int qry(int x,int y=0){for(;x;x-=x&-x)y+=tr[x];return y;}
ll hs(const string&s){
ll h=0;
for(char i:s)h=(h*127+i-95)%P;
return h;
}
int add(int x,const string&s){
for(char i:s){
if(!f[x][i-97])f[x][i-97]=++k;
x=f[x][i-97];
}
return x;
}
int find(int x,const string&s){
for(char i:s)
if(f[x][i-97])x=f[x][i-97];
else return x;//这一行如果不加会随机得分
return x;
}
void dfs(int x){
dfn[x]=++ck;
for(int i=0;i<26;i++)
if(f[x][i])dfs(f[x][i]);
dfm[x]=ck;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n>>m;
for(int i=1;i<=n;i++){
string s1,s2,t0,t1,t2;
cin>>s1>>s2;
int l=0,r=s1.size()-1;
while(l<s1.size()&&s1[l]==s2[l])t1+=s1[l++];
while(r>l&&s1[r]==s2[r])t2+=s1[r--];
for(int j=l;j<=r;j++)t0+=s1[j],t0+=s2[j];
reverse(t1.begin(),t1.end());
reverse(t2.begin(),t2.end());
ll h=hs(t0);
int&z=mp[h];
if(!z)rt[z=++d]=++k,rt[++d]=++k;
c[i]={add(rt[z],t1),add(rt[z+1],t2)};
}
for(int i=1;i<=d;i++)dfs(rt[i]);
for(int i=1;i<=n;i++)
mf[++cnt]={dfn[c[i].fi],dfn[c[i].se],1,0},
mf[++cnt]={dfn[c[i].fi],dfm[c[i].se]+1,-1,0},
mf[++cnt]={dfm[c[i].fi]+1,dfn[c[i].se],-1,0},
mf[++cnt]={dfm[c[i].fi]+1,dfm[c[i].se]+1,1,0};
for(int i=1;i<=m;i++){
string s1,s2,t0,t1,t2;
cin>>s1>>s2;
if(s1.size()!=s2.size())continue;
int l=0,r=s1.size()-1;
while(l<s1.size()&&s1[l]==s2[l])t1+=s1[l++];
while(r>l&&s1[r]==s2[r])t2+=s1[r--];
for(int j=l;j<=r;j++)t0+=s1[j],t0+=s2[j];
reverse(t1.begin(),t1.end());
reverse(t2.begin(),t2.end());
ll h=hs(t0);
if(!mp.count(h))continue;
int z=mp[h];
mf[++cnt]={dfn[find(rt[z],t1)],dfn[find(rt[z+1],t2)],i,1};
}
sort(mf+1,mf+cnt+1,[](node x,node y){
return x.x!=y.x?x.x<y.x:x.t<y.t;
});
for(int i=1;i<=cnt;i++)
if(mf[i].t)ans[mf[i].z]=qry(mf[i].y);
else mdf(mf[i].y,mf[i].z);
for(int i=1;i<=m;i++)cout<<ans[i]<<'\n';
return 0;
}
::::