【Hash】dr所在国度

 

hash

Description

 

dr所在国度的有个奇怪的规定:他们的字母不是a~z,而是用1~1000表示。

利用这个奇怪的规定,dr想出了一个好玩的游戏:首先给出n个字符串(当然每个字符用1~1000表示),然后给出有m个节点的树,节点编号1~m,这棵树以1号节点为根,每个节点都包含一个字符。现在要求用从根节点到其他m-1个节点的链上的字符组成m-1个新字符串(字符的排列顺序为从根到终点的顺序)。

是否这m-1个新字符串中的任意一个串,都与给出的n个字符串中至少一个串匹配呢?

字符串S与字符串T匹配:设len1=|S|,len2=|T|len1=∣S∣,len2=∣T∣,则S_{1}=T_{1},S_{2}=T_{2},...,S_{len1}=T_{len1}S1​=T1​,S2​=T2​,...,Slen1​=Tlen1​ 且 len1 \leq len2len1≤len2

Input

 

第一行输入nn和mm,表示有nn个字符串,树的节点数为m(n \leq 10^3,m \leq 2 * 10^5)m(n≤103,m≤2∗105)

接下来nn行,每行首先输入一个整数kk,代表字符串长度,然后输入kk个整数,代表字符串S_{i}(|Si|,\sum |Si| \leq 2 * 10^5)Si​(∣Si∣,∑∣Si∣≤2∗105)

接下来一行,输入mm个整数C_{i}Ci​,表示树上第ii个节点上的字符

接下来m-1m−1行,每行输入2个整数u,v(1 \leq u,v \leq m)u,v(1≤u,v≤m),表示uu和vv有一条边

Output

 

输出占一行,都能匹配输出YES,否则输出NO

Sample Input 1 

1 4
4 1 2 3 4
1 2 3 2
1 2
2 3
1 4

Sample Output 1

YES

 

#include<cstdio>
#include<algorithm>
#include<map>
#include<cstring>
using namespace std;
typedef long long ll;

map<ll,int>mp;
ll Hash=9731;
int w[200005];

struct node
{
    int v,nxt;
}edge[400005];
int head[400005],ei;

void addedge(int u,int v)
{
    edge[ei].v=v;
    edge[ei].nxt=head[u];
    head[u]=ei++;
}

void init()
{
    memset(head,-1,sizeof(head));
    ei=0;
}
int flag=0;
bool vis[200005]={0};
void dfs(int x,int deep,ll ans,ll sed)
{
    ans+=w[x]*sed;
    sed*=Hash;
    vis[x]=1;
    //printf("%lld ",ans);
    if(mp[ans]==0)flag=1;
    for(int i=head[x];i!=-1;i=edge[i].nxt)
    {
        int v=edge[i].v;
        if(vis[v]==1)continue;
        dfs(v,deep+1,ans,sed);
    }
}

int main()
{
    int n,m;
    init();
    scanf("%d%d",&n,&m);
    for(int i=0;i<n;i++)
    {
        int t;
        scanf("%d",&t);
        ll h=0;
        ll sed=Hash;
        for(int j=0;j<t;j++)
        {
            int x;
            scanf("%d",&x);
            h+=x*sed;
            sed*=Hash;
            mp[h]=1;
        }
    }
    for(int i=1;i<=m;i++)
    {
        scanf("%d",&w[i]);
    }
    for(int i=0;i<m-1;i++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        addedge(v,u);
        addedge(u,v);
    }
    dfs(1,0,0,Hash);
    if(flag==0)printf("YES\n");
    else printf("NO\n");
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值