bzoj2780 广义后缀自动机+parent树+Dfs序+树状数组
2016-01-02 17:18
639 查看
题目:http://www.lydsy.com/JudgeOnline/problem.php?id=2780
大意:给n个串,再给m个询问,询问一个字符串是出现在哪几个母串中。
bzoj2754的强化版。
广义后缀自动机:对于多个串建立后缀自动机,每次只要将last改为1就好了。
这题思路大体同bzoj2434。
但还是具体讲一讲。。。
首先建广义后缀自动机,对于每个节点,记录它属于哪几个串,挂到节点上。然后一样的建parent树,一样的Dfs序。
然后在广义后缀自动机上走询问,如果找不到答案就为0,否则将询问挂到当前节点上。
然后遍历广义后缀自动机,更新答案。
大意:给n个串,再给m个询问,询问一个字符串是出现在哪几个母串中。
bzoj2754的强化版。
广义后缀自动机:对于多个串建立后缀自动机,每次只要将last改为1就好了。
这题思路大体同bzoj2434。
但还是具体讲一讲。。。
首先建广义后缀自动机,对于每个节点,记录它属于哪几个串,挂到节点上。然后一样的建parent树,一样的Dfs序。
然后在广义后缀自动机上走询问,如果找不到答案就为0,否则将询问挂到当前节点上。
然后遍历广义后缀自动机,更新答案。
#include<cstring> #include<cstdio> #include<iostream> #include<algorithm> #include<map> using namespace std; struct sef { int ne,en; }h[400050]; int tt,first[400050]; int ans[400050],n,m; int last,len; int vis[400050]; char s[400050]; struct Tree { sef h[400050]; int tot,first[400040]; int To[400050],Out[400050],tim,d[400050]; inline void setl(int x,int y) { h[++tot].ne=first[x]; h[tot].en=y; first[x]=tot; } inline void Dfs(int x) { int y; To[x]=++tim; d[tim]=x; for (int i=first[x];y=h[i].en,i;i=h[i].ne) Dfs(y); Out[x]=tim; } }G; struct Query { sef h[400050]; int tot,first[400050],w[400050]; inline void setl(int x,int y,int v) { h[++tot].ne=first[x]; h[tot].en=y; w[tot]=v; first[x]=tot; } }Q; struct Fenwick { int d[400050]; inline void Add(const int &x,const int &v) { for (int i=x;i<=G.tim;i+=i & (-i)) d[i]+=v; } inline int Ask(int x) { int r=0; for (int i=G.Out[x];i;i-=i & (-i)) r+=d[i]; for (int i=G.To[x]-1;i;i-=i & (-i)) r-=d[i]; return r; } }fw; struct SAM { map<int , int > son; int len,fa; }C[400040]; int tot; inline void setl(int x,int y) { h[++tt].ne=first[x]; h[tt].en=y; first[x]=tt; } inline void Add(int x,int k) { int p=last,np; if (!C[p].son[x]) { last=np=++tot; C[np].len=C[p].len+1; for (;p&&!C[p].son[x];p=C[p].fa) C[p].son[x]=np; if (!p) C[np].fa=1; else { int q=C[p].son[x]; if (C[p].len+1==C[q].len) C[np].fa=q; else { int nq=++tot; C[nq]=C[q]; C[nq].len=C[p].len+1; C[q].fa=C[np].fa=nq; for (;p&&C[p].son[x]==q;p=C[p].fa) C[p].son[x]=nq; } } } else { int q=C[p].son[x]; if (C[p].len+1==C[q].len) last=q; else { int nq=++tot; C[nq]=C[q]; C[nq].len=C[p].len+1; C[q].fa=nq; for (;p&&C[p].son[x]==q;p=C[p].fa) C[p].son[x]=nq; last=nq; } } setl(last,k); } int main() { scanf("%d%d",&n,&m); tot=1; for (int i=1;i<=n;++i) { scanf("%s",s); len=strlen(s); last=1; for (int j=0;j<len;++j) Add(s[j],i); } for (int i=2;i<=tot;++i) G.setl(C[i].fa,i); G.Dfs(1); int x; bool boo; for (int i=1;i<=m;++i) 4000 { scanf("%s",s); len=strlen(s); x=1; boo=1; for (int j=0;j<len;++j) { if (!C[x].son[s[j]]) { boo=0; break; } else x=C[x].son[s[j]]; } if (boo) Q.setl(G.Out[x],i,x); } int y; for (int j=1;j<=tot;++j) { x=G.d[j]; for (int i=first[x];y=h[i].en,i;i=h[i].ne) { fw.Add(j,1); if (vis[y]) fw.Add(vis[y],-1); vis[y]=j; } for (int i=Q.first[j];y=Q.h[i].en,i;i=Q.h[i].ne) ans[y]=fw.Ask(Q.w[i]); } for (int i=1;i<=m;++i) printf("%d\n",ans[i]); }
相关文章推荐
- BZOJ3275 Number (最小割)
- [bzoj1003] [ZJOI2006]物流运输trans
- [bzoj1500][NOI2005]维修数列
- [bzoj1208] [HNOI2004]宠物收养所
- [bzoj1269][AHOI2006]文本编辑器editort
- [bzoj1503][NOI2004]郁闷的出纳员
- BZOJ1997 2-sat
- bzoj4027 贪心
- [BZOJ2038][2009国家集训队][莫队][分块]小z的袜子
- [BZOJ2594][WC2006][LCT][MST]水管局长数据加强版
- [BZOJ2300][HAOI2011][动态凸包]防线修建
- [BZOJ1045][HAOI2008][贪心]糖果传递
- [BZOJ2539][CTSC2000][KM]丘比特的烦恼
- [BZOJ1004][HNOI2008][Burnside引理][DP]Cards
- [BZOJ1202][HNOI2005][并查集]狡猾的商人
- [BZOJ1179][APIO2009][Tarjan][拓扑排序][递推]Atm
- [BZOJ1095][ZJOI2007][线段树]Hide捉迷藏
- [BZOJ1089][SCOI2003][递推][高精度]严格n元树
- [BZOJ1096][ZJOI2007][DP][斜率优化]仓库建设
- [BZOJ1071][SCOI2007][堆]组队