BZOJ1921: [Ctsc2010]珠寶商(點分治+SAM)
阿新 • • 發佈:2018-12-11
題解: 點分治,如果點數,則結合字尾樹處理出每個位置的開始,結束點並統計答案。否則從每個點開始暴力擴充套件路徑。
時間複雜度。
#include <bits/stdc++.h>
using namespace std;
typedef pair <int,int> pii;
typedef long long LL;
inline int rd() {
char ch=getchar(); int i=0,f=1;
while(!isdigit (ch)) {if(ch=='-') f=-1; ch=getchar();}
while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=getchar();}
return i*f;
}
const int N=1e5+50, B=150;
int n,m,mx,total,G,fa[N];
int sze[N],c1[N],c2[N],vis[N];
char s[N];
long long ans;
vector <int> edge[N];
struct sam {
char ch[N];
int last, tot;
int pos[N],son[N][26],tr[N][26],fail[N],len[N];
int c[N],q[N];
vector <int> edge[N];
sam() {last=tot=1;}
inline void extend(int c,int op) {
int p=++tot; len[p]=len[last]+1; pos[p]=op;
for(;last && !son[last][c];last=fail[last]) son[last][c]=p;
if(!last) fail[p]=1;
else {
int q=son[last][c];
if(len[q]==len[last]+1) fail[p]=q;
else {
int np=++tot; len[np]=len[last]+1; pos[np]=pos[q];
memcpy(son[np],son[q],sizeof(son[np]));
fail[np]=fail[q]; fail[q]=fail[p]=np;
for(;last && son[last][c]==q;last=fail[last]) son[last][c]=np;
}
} last=p;
}
inline void init() {
for(int i=1;i<=m;i++) extend(ch[i]-'a',i);
for(int i=1;i<=tot;i++) if(fail[i]) edge[fail[i]].push_back(i);
for(int i=1;i<=tot;i++) ++c[len[i]];
for(int i=1;i<=tot;i++) c[i]+=c[i-1];
for(int i=tot;i>=1;i--) q[c[len[i]]--]=i;
memset(c,0,sizeof(c));
for(int i=tot;i>=1;i--) {
int u=q[i];
if(pos[u]==len[u]) ++c[u];
if(fail[u]) c[fail[u]]+=c[u];
}
for(int i=1;i<=tot;i++) {
int u=q[i];
for(int e=0,v;e<edge[u].size() && (v=edge[u][e]);++e)
tr[u][ch[pos[v]-len[u]]-'a']=v;
}
memset(q,0,sizeof(q));
}
inline pii trans(pii p,char c) {
if(!p.first) return pii(0,0);
else if(p.second==len[p.first]) return pii(tr[p.first][c-'a'],p.second+1);
else {
if(ch[pos[p.first]-p.second]==c) return pii(p.first,p.second+1);
else return pii(0,0);
}
}
inline int trans2(int p,char c) {return son[p][c-'a'];}
inline void add(pii p) {++q[p.first];}
} ori,rev;
inline void calcG(int x,int f) {
sze[x]=1; int mx_son=0;
for(int e=0,v;e<edge[x].size() && (v=edge[x][e]);++e)
if(!vis[v] && v!=f) {
calcG(v,x);
sze[x]+=sze[v];
mx_son=max(mx_son,sze[v]);
}
mx_son=max(mx_son,total-sze[x]);
if(mx_son<=mx) mx=mx_son, G=x;
}
inline void dfs(int x,int f,pii p1,pii p2) {
p1=ori.trans(p1,s[x]); p2=rev.trans(p2,s[x]);
ori.add(p1); rev.add(p2); sze[x]=1;
for(int e=0,v;e<edge[x].size() && (v=edge[x][e]);++e) if(!vis[v] && v!=f) {
dfs(v,x,p1,p2);
sze[x]+=sze[v];
}
}
inline void dfs(sam &t,int x,int sum,int flag) {
sum+=t.q[x];
if(t.pos[x]==t.len[x]) (flag ? c2[m-t.pos[x]+1] : c1[t.pos[x]])+=sum;;
for(int e=0,v;e<t.edge[x].size() && (v=t.edge[x][e]);++e) dfs(t,v,sum,flag);
}
int rt;
inline void dfs3(int x,int f,int p,int flag) {
if(!p) return;
ans+=flag*ori.c[p];
for(int e=0,v;e<edge[x].size() && (v=edge[x][e]);++e) if(!vis[v] && v!=f) dfs3(v,x,ori.trans2(p,s[v]),flag);
}
inline void dfs2(int x,int f,int flag) {
int p=1;
if(flag<0) {
for(int i=x;;i=fa[i]) {p=ori.trans2(p,s[i]); if(i==rt) break;}
p=ori.trans2(p,s[G]);
}
if(flag<0) dfs3(rt,0,ori.trans2(p,s[rt]),flag);
else dfs3(x,0,ori.trans2(p,s[x]),flag);
for(int e=0,v;e<edge[x].size() && (v=edge[x][e]);++e) if(!vis[v] && v!=f) dfs2(v,x,flag);
}
inline void force_solve(int x,int flag) {
rt=x; dfs2(x,0,flag);
}
inline void calc1(int t) {
for(int i=1;i<=m;i++) c1[i]=c2[i]=0;
dfs(ori,1,0,0);
dfs(rev,1,0,1);
for(int i=1;i<=m;i++) ans+=(LL)c1[i]*c2[i]*t;
for(int i=1;i<=ori.tot;i++) ori.q[i]=0;
for(int i=1;i<=rev.tot;i++) rev.q[i]=0;
}
inline void calc2(int x) {
if(sze[x]<=B) {
force_solve(x,-1);
} else {
pii p(1,0);
dfs(x,G,ori.trans(p,s[G]),rev.trans(p,s[G]));
calc1(-1);
}
}
inline void dfs_pre(int x,int f) {fa[x]=f; for(int e=0,v;e<edge[x].size() && (v=edge[x][e]);++e) if(!vis[v] && v!=f) dfs_pre(v,x);}
inline void solve(int x) {
if(total<=B) force_solve(x,1);
else {
pii p(1,0); vis[x]=1;
ori.add(ori.trans(p,s[x]));
rev.add(rev.trans(p,s[x]));
for(int e=0,v;e<edge[x].size() && (v=edge[x][e]);++e)
if(!vis[v]) dfs_pre(v,x), dfs(v,x,ori.trans(p,s[x]),rev.trans(p,s[x]));
calc1(1);
for(int e=0,v;e<edge[x].size() && (v=edge[x][e]);++e)
if(!vis[v]) calc2(v);
for(int e=0,v;e<edge[x].