BZOJ3881 Coci2015Divljak(AC自动机+树上差分+树状数组)
建出AC自动机及其fail树,每次给新加入的串在AC自动机上经过的点染色,问题即转化为子树颜色数。显然可以用dfs序转成序列问题树状数组套权值线段树解决,显然过不掉。事实上直接树上差分,按dfs序排序后lca处-1,树状数组维护子树和即可。
又一次写了cmp后没放进sort,心态爆炸。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; #define ll long long #define N 2000010 char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;} int gcd(int n,int m){return m==0?n:gcd(m,n%m);} int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } int n,m,trie[N][26],fail[N],val[N],id[N],q[N],tree[N],end[N],tmp[N],cnt; char s[N]; void add(int k,int x){while (k<=cnt) tree[k]+=x,k+=k&-k;} int query(int k){int s=0;while (k) s+=tree[k],k-=k&-k;return s;} namespace Tree { int p[N],t,dfn[N],size[N],fa[N][22],deep[N],cnt; struct data{int to,nxt;}edge[N]; void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;} void dfs(int k) { dfn[k]=++cnt;size[k]=1; for (int i=p[k];i;i=edge[i].nxt) { deep[edge[i].to]=deep[k]+1; fa[edge[i].to][0]=k; dfs(edge[i].to); size[k]+=size[edge[i].to]; } } void build() { cnt=0;dfs(0); for (int j=1;j<22;j++) for (int i=0;i<cnt;i++) fa[i][j]=fa[fa[i][j-1]][j-1]; } int lca(int x,int y) { if (deep[x]<deep[y]) swap(x,y); for (int j=21;~j;j--) if (deep[fa[x][j]]>=deep[y]) x=fa[x][j]; if (x==y) return x; for (int j=21;~j;j--) if (fa[x][j]!=fa[y][j]) x=fa[x][j],y=fa[y][j]; return fa[x][0]; } } void ins(char *s,int n,int p) { int k=0; for (int i=1;i<=n;i++) { if (!trie[k][s[i]-'a']) trie[k][s[i]-'a']=++cnt; k=trie[k][s[i]-'a']; } end[p]=k; } void build() { int head=0,tail=0;for (int i=0;i<26;i++) if (trie[0][i]) q[++tail]=trie[0][i],Tree::addedge(0,trie[0][i]); do { int x=q[++head]; for (int i=0;i<26;i++) if (trie[x][i]) fail[trie[x][i]]=trie[fail[x]][i],Tree::addedge(fail[trie[x][i]],trie[x][i]),q[++tail]=trie[x][i]; else trie[x][i]=trie[fail[x]][i]; }while (head<tail); Tree::build(); } bool cmp(const int&a,const int&b) { return Tree::dfn[a]<Tree::dfn[b]; } void run(char *a,int n) { int k=0,cnt=0;tmp[++cnt]=0; for (int i=1;i<=n;i++) tmp[++cnt]=k=trie[k][a[i]-'a']; sort(tmp+1,tmp+cnt+1,cmp); for (int i=1;i<=cnt;i++) add(Tree::dfn[tmp[i]],1); for (int i=2;i<=cnt;i++) add(Tree::dfn[Tree::lca(tmp[i-1],tmp[i])],-1); } int main() { #ifndef ONLINE_JUDGE freopen("bzoj3881.in","r",stdin); freopen("bzoj3881.out","w",stdout); const char LL[]="%I64d\n"; #else const char LL[]="%lld\n"; #endif m=read(); for (int i=1;i<=m;i++) { scanf("%s",s+1);n=strlen(s+1); ins(s,n,i); } build();cnt++; m=read(); while (m--) { int op=read(); if (op==1) { scanf("%s",s+1);n=strlen(s+1); run(s,n); } else { int x=read(); printf("%d\n",query(Tree::dfn[end[x]]+Tree::size[end[x]]-1)-query(Tree::dfn[end[x]]-1)); } } return 0; }