- 题意:给一个长n的字符串S,q组询问,每组给两个集合A,B。求集合A中的点和集合B中的点所有组合情况的lcp的和。
- 思路:
好像比较常规,可是代码能力差还是调了1.5h。主要还是虚树板子不熟(加入的时候点要去重)
SAM+虚树+虚树上dp
两个后缀的lca相当于后缀树上两个对应节点的LCA的len。
dp就统计每个点为lca的方案数*len[lca]
- code:
#include
using namespace std;
const int N=4e5+5;
char s[N];
typedef long long ll;
int lg[N],a[N],b[N],d[N],pos[N],nxt[N],to[N],head[N],ecnt;
void add_edge(int u,int v) {nxt[++ecnt]=head[u];to[ecnt]=v;head[u]=ecnt;}
struct SAM {
int f[N][21],dep[N],ch[N][27],t[N],len[N],lst,num,par[N],sz[N],Head[N],To[N],Nxt[N],Ecnt,In[N],Out[N],Time;
SAM() {lst=num=1;}
void Add_edge(int u,int v) {Nxt[++Ecnt]=Head[u];To[Ecnt]=v;Head[u]=Ecnt;}
int Insert(int x) {
int p=lst,np=++num;lst=np;len[np]=len[p]+1;sz[np]=1;
for(;!ch[p][x];p=par[p]) ch[p][x]=np;
if(!p) {par[np]=1;return np;}
int q=ch[p][x];
if(len[q]==len[p]+1) {par[np]=q;return np;}
int nq=++num;par[nq]=par[q];len[nq]=len[p]+1;
for(int j=0;j<26;j++)ch[nq][j]=ch[q][j];
par[q]=par[np]=nq;
for(;ch[p][x]==q;p=par[p])ch[p][x]=nq;
return np;
}
void dfs(int u) {
In[u]=++Time;
for(int i=Head[u];i;i=Nxt[i]) {
int v=To[i];
dep[v]=dep[u]+1;f[v][0]=u;
for(int j=1;j<=lg[dep[v]];j++) f[v][j]=f[f[v][j-1]][j-1];
dfs(v);
}
Out[u]=Time;
}
void bd_Fail() {
for(int i=1;i<=num;i++) if(par[i])Add_edge(par[i],i);
dfs(1);
}
int Lca(int u,int v) {
if(dep[u]=0;i--) if(f[u][i]!=f[v][i])u=f[u][i],v=f[v][i];
return f[u][0];
}
}A;
bool cmp(int u,int v) {return A.In[u]=0;i--)pos[i+1]=A.Insert(s[i]-'a');
lg[1]=0;for(int i=2;i<=(n<<1);i++)lg[i]=lg[i>>1]+1;
A.bd_Fail();
while(q--) {
int ca,cb,up=0;
scanf("%d%d",&ca,&cb);
for(int i=1;i<=ca;i++) {scanf("%d",&a[i]);d[++up]=a[i]=pos[a[i]];mark[a[i]]=1;}
for(int i=1;i<=cb;i++) {scanf("%d",&b[i]);b[i]=pos[b[i]];if(!mark[b[i]])d[++up]=b[i],mark[b[i]]=1;}
sort(d+1,d+1+up,cmp);
for(int i=1,sz=up;iA.Out[st[tp]]))tp--;
if(tp)add_edge(st[tp],d[i]);
// printf("!%d %d\n",st[tp],d[i]);
st[++tp]=d[i];
}
for(int i=1;i<=ca;i++)sa[a[i]]=1;
for(int i=1;i<=cb;i++)sb[b[i]]=1;
DP(d[1]);
printf("%lld\n",ans);
tp=ecnt=ans=0;for(int i=1;i<=up;i++)mark[d[i]]=sa[d[i]]=sb[d[i]]=head[d[i]]=0;
}
return 0;
}