样例输入
3
a#a
#
aczra#
样例输出
3
分析
维护两个Trie树
第一个维护第一个#前的前缀
第二个维护最后一个#后的后缀
我们发现,只要前缀包涵,后缀包涵,一定合法
什么意思...
abcde # bcd
abcd # abcd
abcde 包涵 abcd
abcd 包涵 bcd 它们是合法的
所以我们维护第一棵树上的节点对应第二棵树上的哪一个
一边dfs第一棵,一边更新第二棵
与第二棵可能相同的就是到根的所有个数和子树个数
dfs序维护路径,子树和就可以了
代码
#include<bits/stdc++.h>
#define N 1000050
using namespace std;
vector<int> S[N];
char s[N]; int c1[N],c2[N];
int ch[N][30],n,tot=2;long long ans;
int To[N],st[N],ed[N],sign;
int read(){
int cnt=0,f=1;char ch=0;
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch))cnt=cnt*10+(ch-'0'),ch=getchar();
return cnt;
}
void Insert_pre(int id){
int len=strlen(s),now=1;
for(int i=0;s[i]!='#';i++){
if(!ch[now][s[i]-'a']) ch[now][s[i]-'a']=++tot;
now=ch[now][s[i]-'a'];
}
S[now].push_back(id);
}
int Insert_sub(){
int len=strlen(s),now=2;
for(int i=len-1;s[i]!='#';i--){
if(!ch[now][s[i]-'a']) ch[now][s[i]-'a']=++tot;
now=ch[now][s[i]-'a'];
}
return now;
}
int quary1(int x){
int ans=0;
for(;x;x-=x&-x) ans+=c1[x];
return ans;
}
int quary2(int x){
int ans=0;
for(;x;x-=x&-x) ans+=c2[x];
return ans;
}
void update1(int x,int val){
for(;x<=tot;x+=x&-x) c1[x]+=val;
}
void update2(int x,int val){
for(;x<=tot;x+=x&-x) c2[x]+=val;
}
void dfs2(int u){
st[u]=++sign;
for(int i=0;i<26;i++)
if(ch[u][i]) dfs2(ch[u][i]);
ed[u]=sign;
}
void dfs(int u){
for(int i=S[u].size()-1;i>=0;i--){
int v=To[S[u][i]];
ans+=quary1(st[v]);
ans+=quary2(ed[v])-quary2(st[v]);
update1(st[v],1),update1(ed[v]+1,-1);
update2(st[v],1);
}
for(int i=0;i<26;i++)
if(ch[u][i]) dfs(ch[u][i]);
for(int i=S[u].size()-1;i>=0;i--){
int v=To[S[u][i]];
update1(st[v],-1),update1(ed[v]+1,1);
update2(st[v],-1);
}
}
int main(){
n=read();
for(int i=1;i<=n;i++){
scanf("%s",s);
Insert_pre(i);
To[i]=Insert_sub();
}
dfs2(2);dfs(1);
printf("%lld",ans);
return 0;
}