BJ模拟 相似子串【哈希+并查集】

题目描述:

这里写图片描述

解题思路:

把26个字母分开hash,每一位只用0和1表示这一位是否是字母i。
询问时也把26个字母分开比较,把等价类里的hash加起来算。
不同处最多为1,即是最后的hash值只会有一个形如 b a s e i 的差,判断一下即可。

#include<bits/stdc++.h>
#define ll unsigned long long
using namespace std;
int getint()
{
    int i=0,f=1;char c;
    for(c=getchar();c!='-'&&(c<'0'||c>'9');c=getchar());
    if(c=='-')f=-1,c=getchar();
    for(;c>='0'&&c<='9';c=getchar())i=(i<<3)+(i<<1)+c-'0';
    return i*f;
}
const int N=100005,C=26;
const ll base=123LL,invbase=3449391168254631603LL;
int n,m,id[N];
int tot,first[N],nxt[N<<1],to[N<<1],c[N<<1];
int dep[N],fa[N][20];
ll bin[N],binv[N],g[N][26],f[N][26],sum1[C],sum2[C];
map<ll,bool>mp;
int find(int x){return id[x]==x?x:id[x]=find(id[x]);}
void merge(int x,int y){id[find(y)]=find(x);}
void add(int x,int y,int z)
{
    nxt[++tot]=first[x],first[x]=tot,to[tot]=y,c[tot]=z;
}
void dfs(int u)
{
    for(int i=1;i<20;i++)fa[u][i]=fa[fa[u][i-1]][i-1];
    for(int e=first[u];e;e=nxt[e])
    {
        int v=to[e];
        if(v==fa[u][0])continue;
        fa[v][0]=u,dep[v]=dep[u]+1;
        for(int i=0;i<C;i++)
        {
            g[v][i]=g[u][i]+bin[dep[v]]*(c[e]==i);
            f[v][i]=f[u][i]*base+(c[e]==i);
        }
        dfs(v);
    }
}
int lca(int x,int y)
{
    if(dep[x]<dep[y])swap(x,y);
    int det=dep[x]-dep[y];
    for(int i=0;i<20;i++)if(det>>i&1)x=fa[x][i];
    for(int i=19;i>=0;i--)if(fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i];
    return x==y?x:fa[x][0];
}
ll gethash(int u,int v,int t,int i)
{
    ll s1=(g[u][i]-g[t][i])*binv[dep[t]];
    ll s2=f[v][i]-f[t][i]*bin[dep[v]-dep[t]];
    return s1*bin[dep[v]-dep[t]]+s2;
}
bool check(int u1,int v1,int u2,int v2)
{
    int t1=lca(u1,v1),t2=lca(u2,v2);
    if(dep[u1]+dep[v1]-2*dep[t1]!=dep[u2]+dep[v2]-2*dep[t2])return false;
    for(int i=0;i<C;i++)sum1[i]=sum2[i]=0;
    for(int i=0;i<C;i++)
    {
        sum1[id[i]]+=gethash(u1,v1,t1,i);
        sum2[id[i]]+=gethash(u2,v2,t2,i);
    }
    int cnt=0;
    for(int i=0;i<C;i++)if(id[i]==i)
    {
        if(sum1[i]==sum2[i])continue;
        if(!mp.count(sum1[i]-sum2[i]))return false;
        cnt++;
    }
    return cnt<=2;
}
int main()
{
    //freopen("lx.in","r",stdin);
    int x,y,z;
    n=getint();
    bin[0]=binv[0]=1,mp[1]=mp[-1]=1;
    for(int i=1;i<=n;i++)
    {
        bin[i]=bin[i-1]*base,binv[i]=binv[i-1]*invbase;
        mp[bin[i]]=mp[-bin[i]]=1;
    }
    for(int i=1;i<n;i++)
    {
        x=getint(),y=getint(),z=getchar()-'a';
        add(x,y,z),add(y,x,z);
    }
    dfs(1);
    m=getint();int k,u1,v1,u2,v2;char ch[2];
    while(m--)
    {
        k=getint(),u1=getint(),v1=getint(),u2=getint(),v2=getint();
        for(int i=0;i<C;i++)id[i]=i;
        while(k--)scanf("%s",ch),merge(ch[0]-'a',ch[1]-'a');
        for(int i=0;i<C;i++)find(i);
        check(u1,v1,u2,v2)?puts("YES"):puts("NO");
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/cdsszjj/article/details/80033693
bj
今日推荐