1. 程式人生 > >BZOJ1921: [Ctsc2010]珠寶商(點分治+SAM)

BZOJ1921: [Ctsc2010]珠寶商(點分治+SAM)

傳送門

題解: 點分治,如果點數n\ge \sqrt{n},則結合字尾樹O(sze+m)O(sze+m)處理出每個位置的開始,結束點並統計答案。否則從每個點開始暴力擴充套件路徑。

時間複雜度O(nn)O(n \sqrt{n})

#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].