【WC2016模拟】打击目标
来源:互联网 发布:牛肉汤成本算法 编辑:程序博客网 时间:2024/06/05 17:44
Description
Input
Output
Sample Input
3 0
xyz xy x
1 2
2
1 3 xyz
2 3 zzzzxy
Sample Output
3
2
Data Constraint
题解
这一题在比赛的时候我已经想到了和题解基本一样的做法,然而因为不会树剖(雾,所以只打了50point,结果数据超级水,要不是开小了数组就AC了QvQ
下午赶紧学习了一下树剖,然后发现是一个超级简单的东西,就是维护出每一个点对应的重链的上面的顶点是什么,然后看哪边深就跳哪边就好了
那么这一题怎么做呢?
收先看到多串匹配条件反射的就想到了SA和AC自动机
看了一下发现就是一个AC自动机
某一个串经过的自动机中某一节点沿着fail能跳到的就是它的子串
那么我们不妨对自动机中的每一个点挂一个可持久化线段树,然后沿着fail边不断的更新就好了
询问的话因为树剖了一下所以只有log段,复杂度应该是两个log的
贴代码
打的不是很优美。。。
#include<iostream>#include<algorithm>#include<cstdio>#include<cstring>#include<cmath>#define fo(i,a,b) for(i=a;i<=b;i++)#define fo1(i,b,a) for(i=b;i>=a;i--)#define max(x,y) ((x)>(y)?(x):(y))using namespace std;const int maxn=1e5+5;int tree[maxn*10][27],fail[maxn*10],h[maxn*10];int tr[maxn*50][3];int ff[maxn][18];int cc[maxn*10],de[maxn],dep[maxn*10];int fi[maxn],ne[maxn*2],dui[maxn*2],qc[maxn],siz[maxn];int fi1[maxn*3],ne1[maxn*5],dui1[maxn*5],qc1[maxn*3];int fa[maxn],dfn[maxn],top[maxn],go[maxn],root[maxn*10];bool bq;int i,j,k,l,m,n,x,y,z,o,ans,now,q,xz,zo,zz,cz,mx,xx,yy,p,xc;char s[maxn];void add(int x,int y){ if (fi[x]==0) fi[x]=++mx; else ne[qc[x]]=++mx; dui[mx]=y; qc[x]=mx;}void add1(int x,int y){ if (fi1[x]==0) fi1[x]=++mx; else ne1[qc1[x]]=++mx; dui1[mx]=y; qc1[x]=mx;}void ge_a(){ k=0; fo(i,1,26) if (tree[0][i]) h[++k]=tree[0][i]; i=k; j=0; while (i>j){ j++; x=h[j]; fo(k,1,26) if (tree[x][k]){ now=fail[x]; while (tree[now][k]==0 && now>0) now=fail[now]; if (tree[now][k]) now=tree[now][k]; fail[tree[x][k]]=now; h[++i]=tree[x][k]; } }}void ge_ff(){ fo(j,1,16) fo(i,1,n) ff[i][j]=ff[ff[i][j-1]][j-1];}int lca(int x,int y){ if (de[x]<de[y]){ int z=x; x=y; y=z; } fo1(i,16,0) if (de[x]-(1<<i)>=de[y]) x=ff[x][i]; fo1(i,16,0) if (ff[x][i]!=ff[y][i]){ x=ff[x][i]; y=ff[y][i]; } if (x!=y) x=ff[x][0]; return x;}void dfs(int x){ int i=fi[x]; siz[x]=1; while (i){ de[dui[i]]=de[x]+1; dfs(dui[i]); siz[x]+=siz[dui[i]]; if (siz[dui[i]]>siz[go[x]]) go[x]=dui[i]; i=ne[i]; }}void dfss(int x){ dfn[x]=++now; top[go[x]]=top[x]; if (go[x]) dfss(go[x]); int i=fi[x]; while (i){ if (dui[i]==go[x]){ i=ne[i]; continue; } top[dui[i]]=dui[i]; dfss(dui[i]); i=ne[i]; }}void maketree(int v,int s1,int s2,int l,int r){ tr[++p][0]=tr[v][0]; tr[p][1]=tr[v][1]; tr[p][2]=tr[v][2]; int q=p; if (l==r){ tr[p][2]=s2; return; } int mid=(l+r)/2; if (s1<=mid){ tr[p][0]=p+1; maketree(tr[v][0],s1,s2,l,mid); } else{ tr[p][1]=p+1; maketree(tr[v][1],s1,s2,mid+1,r); } tr[q][2]=max(tr[tr[q][0]][2],tr[tr[q][1]][2]);}void wor(int x){ if (! root[fail[x]] && fail[x]) wor(fail[x]); if (fi1[x]){ int pp=fi1[x]; root[x]=p+1; maketree(root[fail[x]],dfn[dui1[pp]],dep[x],1,n); pp=ne1[pp]; while (pp){ int qq=p+1; maketree(root[x],dfn[dui1[pp]],dep[x],1,n); root[x]=qq; pp=ne1[pp]; } } else root[x]=root[fail[x]];}void find(int v,int l,int r,int x,int y){ if (l==x && r==y) ans=max(ans,tr[v][2]); else{ int mid=(l+r)/2; if (y<=mid) find(tr[v][0],l,mid,x,y); else if (x>mid) find(tr[v][1],mid+1,r,x,y); else{ find(tr[v][0],l,mid,x,mid); find(tr[v][1],mid+1,r,mid+1,y); } }}void tur(int q){ xx=x; yy=y; while (top[xx]!=top[yy]){ if (de[top[xx]]<de[top[yy]]){ find(root[q],1,n,dfn[top[yy]],dfn[yy]); yy=fa[top[yy]]; } else{ find(root[q],1,n,dfn[top[xx]],dfn[xx]); xx=fa[top[xx]]; } } if (dfn[xx]>dfn[yy]){ z=xx; xx=yy; yy=z; } find(root[q],1,n,dfn[xx],dfn[yy]);}int main(){// freopen("t2.in","r",stdin);// freopen("t2.out","w",stdout); scanf("%d%d",&n,&o); fo(i,1,n){ scanf("%s",s+1); l=strlen(s+1); now=0; fo(j,1,l){ x=s[j]-96; if (tree[now][x]) now=tree[now][x]; else{ tree[now][x]=zo+1; dep[++zo]=dep[now]+1; now=tree[now][x]; } } add1(now,i); } ge_a(); mx=0; fo(i,2,n){ scanf("%d",&ff[i][0]); fa[i]=ff[i][0]; add(ff[i][0],i); } ge_ff(); now=0; dfs(1); top[1]=1; dfss(1); p=0; fo(i,1,zo) if (! root[i]) wor(i); scanf("%d",&q); ans=0; fo(xz,1,q){ scanf("%d%d",&x,&y); if (o){ x^=ans; y^=ans; } xx=x; yy=y; z=lca(x,y); now=0; scanf("%s",s+1); l=strlen(s+1); ans=0; fo(i,1,l){ xc=s[i]-96; while (now>0 && tree[now][xc]==0) now=fail[now]; if (tree[now][xc]) now=tree[now][xc]; tur(now); } printf("%d\n",ans); } return 0;}
阅读全文