BJ模拟:相似子串(树链剖分+hash)

来源:互联网 发布:linux mysql 远程连接 编辑:程序博客网 时间:2024/06/06 13:03

这里写图片描述

题解:
这里写图片描述
树上hash值用链剖来维护。

代码:

#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<string>#include<algorithm>#include<cmath>#include<vector>#include<map>using namespace std;typedef long long ll;const int Maxn=4e6+50;const int G=3;inline int read(){    char ch=getchar();int i=0,f=1;    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}    while(ch>='0'&&ch<='9'){i=(i<<3)+(i<<1)+ch-'0';ch=getchar();}    return i*f;}int n,tot,fa[Maxn],top[Maxn],dep[Maxn],val[Maxn],idx[Maxn],son[Maxn],sze[Maxn],pos[Maxn],anc[Maxn];struct node{    int to,val;    node(int to=0,int val=0):to(to),val(val){}};vector<node>edge[Maxn];map<ll,int>S;ll h1[27][Maxn],h2[27][Maxn],powG[Maxn];inline void Insert(int x,int y,int val){    edge[x].push_back(node(y,val));    edge[y].push_back(node(x,val));}inline void Dfs1(int now,int f=0){    fa[now]=f;dep[now]=dep[f]+1;sze[now]=1;    for(int v,e=edge[now].size()-1;e>=0;e--)    {        v=edge[now][e].to;        if(v^f)        {            Dfs1(v,now);            sze[now]+=sze[v];            val[v]=edge[now][e].val;            if(sze[son[now]]<sze[v])son[now]=v;        }    }}inline void Dfs2(int now,int f=0){    if(son[now])    {        idx[pos[son[now]]=++tot]=son[now];        top[son[now]]=top[now];        Dfs2(son[now],now);    }    for(int v,e=edge[now].size()-1;e>=0;e--)    {        v=edge[now][e].to;        if(v^son[now]&&v^f)        {            idx[pos[v]=++tot]=v;            top[v]=v;            Dfs2(v,now);        }    }}inline void SplitTree(){    Dfs1(1);    tot=top[1]=idx[1]=pos[1]=1;    Dfs2(1);}inline int getf(int i){    if(anc[i]==i)return i;    return anc[i]=getf(anc[i]);}inline int Getlca(int x,int y){    while(top[x]^top[y])    {        if(dep[top[x]]<dep[top[y]])swap(x,y);        x=fa[top[x]];    }    return dep[x]<dep[y]?x:y;}inline int Getlen(int x,int y){    int lca=Getlca(x,y);    return dep[x]+dep[y]-2*dep[lca];}inline ll GetH1(int id,int x,int y){    return h1[id][y]-powG[y-x+1]*h1[id][x-1];}inline ll GetH2(int id,int x,int y){    return h2[id][x]-powG[y-x+1]*h2[id][y+1];}inline ll GetH(int i,int x,int y){    int lca=Getlca(x,y);    ll s1=0,s2=0;    ll tmp1=1,tmp2=powG[dep[x]-dep[lca]];    while(top[x]^top[lca])    {        s1+=tmp1*GetH1(i,pos[top[x]],pos[x]);        tmp1*=powG[dep[x]-dep[top[x]]+1];        x=fa[top[x]];    }    if(x^lca)s1+=tmp1*GetH1(i,pos[lca]+1,pos[x]);    while(top[y]^top[lca])    {        s2=s2*powG[dep[y]-dep[top[y]]+1]+GetH2(i,pos[top[y]],pos[y]);        y=fa[top[y]];    }    if(y^lca)s2=s2*powG[dep[y]-dep[lca]]+GetH2(i,pos[lca]+1,pos[y]);    return s1+tmp2*s2;}inline bool query(){    int m=read(),xx1=read(),yy1=read(),xx2=read(),yy2=read();    if(Getlen(xx1,yy1)!=Getlen(xx2,yy2))return false;    static ll t1[27],t2[27];    static ll b[27];    static char ch[3];    for(int i=1;i<=26;i++)    t1[i]=GetH(i,xx1,yy1),t2[i]=GetH(i,xx2,yy2);    for(int i=1;i<=26;i++)anc[i]=i;    while(m--)    {        scanf("%s",ch+1);        int x=ch[1]-'a'+1,y=ch[2]-'a'+1;        if(getf(x)!=getf(y))anc[anc[x]]=anc[y];    }    for(int i=1;i<=26;i++)    {        if(getf(i)^i)        {            t1[getf(i)]+=t1[i],t2[getf(i)]+=t2[i];        }    }    ll cnt=0;    for(int i=1;i<=26;i++)    {        if(getf(i)==i)        {            ll tmp=t1[i]-t2[i];            if(S.count(tmp))            {                cnt++;                b[i]=tmp;            }            else if(tmp==0)b[i]=0;            else return false;        }        else b[i]=0;    }    if(!cnt)return true;    if(cnt^2) return false;    cnt=0;    for(int i=1;i<=26;i++)    {        cnt+=b[i];    }    return cnt==0;}int main(){    n=read();    powG[0]=1;    for(int i=1;i<=n;i++)    {        powG[i]=powG[i-1]*G;        if(!S.count(powG[i]))        {            S[powG[i]]=i;        }        if(!S.count(-powG[i]))        {            S[-powG[i]]=-i;        }    }    S[1]=1;S[-1]=-1;    for(int i=1;i<n;i++)    {        int x=read(),y=read();        char c;scanf("%c",&c);        Insert(x,y,c-'a'+1);     }    SplitTree();    for(int i=1;i<=26;i++)    {        h1[i][0]=0;        for(int j=1;j<=n;j++)        {            h1[i][j]=h1[i][j-1]*G+(val[idx[j]]==i?1:0);        }        h2[i][n+1]=0;        for(int j=n;j>=1;j--)        {            h2[i][j]=h2[i][j+1]*G+(val[idx[j]]==i?1:0);        }    }    int Q=read();    while(Q--)    {        if(query())puts("YES");        else puts("NO");    }}
0 0
原创粉丝点击