标签:vector space void using mina 区间 opera https continue
给你一个串 $ S $ 以及一个字符串数组 $ T_1 ~ T_m $ , $ q $ 次询问,每次问 $ S $ 的子串S[p_l,p_r]在 $ T_l ~ T_r $ 中的哪个串里的出现次数最多,并输出出现次数。
如有多解输出最靠前的那一个。
SAM的毒瘤题,无论是倍增来满足长度限制,线段树合并来求区间询问,应有尽有。。。
对于 $ T $ 串建广义SAM,之后考虑如何使得 $ S $ 在SAM上匹配时求出 $ S $ 在每个 $ T $ 的出现次数。
很明显用线段树合并就可以搞:
每插入 $ T_i $ 的一个字符就在 $ fin $ 上挂上一个 $ i $ 。
然后跳parent树搞线段树合并就好。
之后,由于每次 $ S $ 也只选中一部分,所以考虑:
对于一组询问 $ [l,r,pl,pr] $ ,首先毫无疑问将询问挂在 $ S $ 的 $ pr $ 位上。
之后匹配到 $ pr $ 位时,倍增跳现所处点 $ px $ 的 $ pre $ 到最上面的 $ x $ 使得 $ len[x]>=(pr-pl+1) $ 。
然后线段树上求答案即可。
#include<bits/stdc++.h>
using namespace std;
namespace RKK
{
const int N=1000011;
int n,m,qaq;
char s0[N],s1[N];int l0,l1;
struct sumireko{int to,ne;}e[N];int he[N],ecnt;
void addline(int f,int t){e[++ecnt].to=t;e[ecnt].ne=he[f];he[f]=ecnt;}
int fa[N][22];
int tcnt,rt[N],lson[N<<3],rson[N<<3];
struct pat
{
int first,second;
bool operator < (const pat &a)const{return second==a.second?first>a.first:second<a.second;}
};
pat ma[N<<3],ans[N];
void fuckup(int px){ma[px]=max(ma[lson[px]],ma[rson[px]]);}
void insert(int x,int &px,int pl,int pr)
{
if(!px) px=++tcnt;
if(pl==pr)
{
ma[px].first=x,ma[px].second++;
return;
}
int pm=pl+pr>>1;
if(x<=pm) insert(x,lson[px],pl,pm);
else insert(x,rson[px],pm+1,pr);
fuckup(px);
}
int merge(int px,int py,int pl,int pr)
{
if(!px||!py) return px|py;
int pz=++tcnt;
if(pl==pr){ma[pz]=(pat){pl,ma[px].second+ma[py].second};}
else
{
int pm=pl+pr>>1;
lson[pz]=merge(lson[px],lson[py],pl,pm);
rson[pz]=merge(rson[px],rson[py],pm+1,pr);
fuckup(pz);
}
return pz;
}
void query(int l,int r,int px,int pl,int pr,pat &pa)
{
if(!px) return;
if(l<=pl&&r>=pr){pa=max(pa,ma[px]);return;}
int pm=pl+pr>>1;
if(l<=pm) query(l,r,lson[px],pl,pm,pa);
if(r>pm) query(l,r,rson[px],pm+1,pr,pa);
}
struct ques{int p,le,l,r,id;};
vector<ques> ve[N];
struct remilia{int tranc[26],len,pre;};
struct sakuya
{
remilia s[N];
int fin,size;
sakuya(){fin=size=1;}
void ins(int ch)
{
int npx,npy,lpx,lpy;
if(s[fin].tranc[ch])
{
lpx=fin,lpy=s[fin].tranc[ch];
if(s[lpy].len==s[lpx].len+1) fin=lpy;
else
{
npy=++size;
s[npy]=s[lpy];
s[npy].len=s[lpx].len+1;
s[lpy].pre=npy;
while(s[lpx].tranc[ch]==lpy)
{
s[lpx].tranc[ch]=npy;
lpx=s[lpx].pre;
}
fin=npy;
}
return;
}
npx=++size;
s[npx].len=s[fin].len+1;
for(lpx=fin;lpx&&!s[lpx].tranc[ch];lpx=s[lpx].pre) s[lpx].tranc[ch]=npx;
if(!lpx) s[npx].pre=1;
else
{
lpy=s[lpx].tranc[ch];
if(s[lpy].len==s[lpx].len+1) s[npx].pre=lpy;
else
{
npy=++size;
s[npy]=s[lpy];
s[npy].len=s[lpx].len+1;
s[npx].pre=s[lpy].pre=npy;
while(s[lpx].tranc[ch]==lpy)
{
s[lpx].tranc[ch]=npy;
lpx=s[lpx].pre;
}
}
}
fin=npx;
}
void dfs(int x)
{
for(int i=he[x],t=e[i].to;i;i=e[i].ne,t=e[i].to)
{
dfs(t),rt[x]=merge(rt[x],rt[t],1,m);
}
}
void work()
{
for(int i=2;i<=size;i++) fa[i][0]=s[i].pre,addline(s[i].pre,i);
for(int k=1;k<=21;k++)for(int i=2;i<=size;i++) fa[i][k]=fa[fa[i][k-1]][k-1];
dfs(1);
int px=1,lnow=0;
for(int i=1;i<=l0;i++)
{
while(px&&!s[px].tranc[s0[i]-'a']) px=s[px].pre,lnow=s[px].len;
if(!px) px=1,lnow=0;
else px=s[px].tranc[s0[i]-'a'],lnow++;
for(int j=0;j<ve[i].size();j++)
{
ques &qn=ve[i][j];
ans[qn.id].first=qn.l;
if(lnow<qn.le){continue;}
int x=px;
for(int k=21;k>=0;k--)if(s[fa[x][k]].len>=qn.le) x=fa[x][k];
query(qn.l,qn.r,rt[x],1,m,ans[qn.id]);
}
}
}
}sam;
int Iris()
{
scanf("%s",s0+1),l0=strlen(s0+1);
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
scanf("%s",s1+1),l1=strlen(s1+1);
sam.fin=1;
for(int j=1;j<=l1;j++) sam.ins(s1[j]-'a'),insert(i,rt[sam.fin],1,m);
}
scanf("%d",&qaq);
for(int i=1,l,r,x,y;i<=qaq;i++)
{
scanf("%d%d%d%d",&l,&r,&x,&y);
ve[y].push_back((ques){y,y-x+1,l,r,i});
}
sam.work();
for(int i=1;i<=qaq;i++)
printf("%d %d\n",ans[i].first,ans[i].second);
return 0;
}
}
int main(){return RKK::Iris();}
CF666E Forensic Examination(广义后缀自动机+线段树合并)
标签:vector space void using mina 区间 opera https continue
原文地址:https://www.cnblogs.com/rikurika/p/12079264.html