做题之前:学会Hash表,用long long !!!!!!!!!!


这道题要求在线算法、一个Hash对应(7进制)、合并+分离

一头雾水………………

阅读题目次数*998244353……………………

k<=50直接上暴力合并拆解

其余的Hash表维护

具体看代码吧

#include<cstdio>
#include<cstring>
#define _for(i,a,b) for(register int i=(a) ;i<=(b);i=-~i)
#define __for(i,a,b) for(register int i=(a);i>=(b);i=~-i)
#define Re register int
using namespace std;
typedef long long ll;
const int N=2e5+20,P=19260817,Q=1e7+20,mod=998244353;
inline int re(){int x=0,f=0;
    char ch=getchar();
    while(ch>'9'||ch<'0')
        f|=ch=='-',ch=getchar();
    while(ch>='0'&&ch<='9')
        x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    return f?-x:x;
}

int n,m,cnt,head[P+10],nxt[N],bef[N],val[N];
ll p[100],p10[100],num[100];
char s[Q];

struct zu
{
    int nxt,num;
    ll val;
}hashtable[P+10];

inline void add(ll Hash,ll q)
//Hash表如果有Hash这个值&&有这个原值q,num++,否则新开一个点
{
    for(Re i=head[Hash];i;i=hashtable[i].nxt)
        if(hashtable[i].val==q)
        {
            hashtable[i].num++;
            return ;
        }
    hashtable[++cnt].num=1;
    hashtable[cnt].val=q;
    hashtable[cnt].nxt=head[Hash];
    head[Hash]=cnt;
}

inline void dlt (ll Hash,ll q)
{
    for(Re i=head[Hash];i;i=hashtable[i].nxt)
        if(hashtable[i].val==q)
        {
            hashtable[i].num--;//删除同理,就是加变减,题目保证有解
            return ;
        }
}

inline int ask(ll Hash,ll q)
{
    for(Re i=head[Hash];i;i=hashtable[i].nxt)
        if(hashtable[i].val==q)//同理返回队列长度
            return hashtable[i].num;
    return 0;//没这么长的长度返回0
}

int s1[100],s2[100];

void unionn(int u,int v)
{
    int l1=0,l2=0;
    ll hash1=0,q1=0,hash2=0,q2=0;
    nxt[u]=v;
    bef[v]=u;
    for(Re i=u;i&&l1<49;i=bef[i])
    {//将u与u之前最长50的串取出来,注意在s1中的串是反着的
        s1[++l1]=val[i];
        hash1=(hash1+val[i]*p[l1-1])%P;
        q1+=(val[i]*p10[l1-1]);
    }
    for(Re i=v;i&&l2<49;i=nxt[i])
        s2[++l2]=val[i];
    //将v与v之后最长50的串取出来,注意在s2中的串是正着的
    __for(i,l1,1)
    {//s1是反串,最前面的字符在l1的位置,所以倒序枚举
        hash2=0;
        q2=0;
        for(Re j=1;j<=l2&&i+j<=50;j++)
        {//s2是正串,最后面的字符在1的位置,所以正序枚举
            hash2=(hash2*7+s2[j])%P;
            q2=q2*10+s2[j];//Hash值与原值累加,塞到Hash表中
            add((hash1*p[j]%P+hash2)%P,q1*p10[j]+q2);
        }
        hash1=((hash1-p[i-1]*s1[i])%P+P)%P;
        q1-=(p10[i-1]*s1[i]);
        //将hash1和q1向下减
    }
}

void cut (int u,int v)
{//来一句与合并同理,行吗?O(∩_∩)O哈哈~
    int l1=0,l2=0;
    ll hash1=0,hash2,q1=0,q2;
    nxt[u]=0;
    bef[v]=0;
    for(Re i=u;i&&l1<49;i=bef[i])
    {
        s1[++l1]=val[i];
        hash1=(hash1+val[i]*p[l1-1])%P;
        q1+=(val[i]*p10[l1-1]);
    }
    for(Re i=v;i&&l2<49;i=nxt[i])
        s2[++l2]=val[i];
    __for(i,l1,1)
    {
        hash2=0;
        q2=0;
        for(Re j=1;i+j<=50&&j<=l2;j++)
        {
            hash2=(hash2*7+s2[j])%P;
            q2=q2*10+s2[j];
            dlt((hash1*p[j]%P+hash2)%P,q1*p10[j]+q2);
        }
        hash1=((hash1-p[i-1]*s1[i])%P+P)%P;
        q1-=(s1[i]*p10[i-1]);
    }
}

int main()
{
    n=re(),m=re();
    _for(i,1,n)
        val[i]=re(),num[val[i]]++;
    p[0]=p10[0]=1;
    _for(i,1,50)
        p[i]=p[i-1]*7%P,p10[i]=p10[i-1]*10;
    //之所以用7,是因为题目保证蚯蚓长度不超过6
    int op,x,y,len,k;
    ll Hash,q,ans;
    while(m--)
    {
        op=re();
        if(op==1)
        {//合并x,y
            x=re(),y=re();
            unionn(x,y);
        }
        else if(op==2)
        {//分离x,x的下一个
            x=re();
            cut(x,nxt[x]);
        }
        else
        {
            scanf("%s",s+1);
            k=re();
            len=strlen(s+1);
            Hash=q=0;
            ans=1;
            if(k==1)
            //特别的,如果询问长度为1的串,因为之前我也没有加过,所以在读入的时候开一个桶来统计答案
            {
                _for(i,1,len)
                    ans=ans*num[s[i]^48]%mod;
                printf("%lld\n",ans);
                continue;
            }
            _for(i,1,k)
            {
                Hash=(Hash*7+(s[i]^48))%P;
                q=q*10+(s[i]^48);
            }
            ans=ask(Hash,q)%mod;
            _for(i,k+1,len)
            {
                Hash=(((Hash-(s[i-k]^48)*p[k-1]%P+P)%P)*7+(s[i]^48))%P;
                q=(q-(s[i-k]^48)*p10[k-1])*10+(s[i]^48);
                //更新原值和Hash值
                ans=ans*ask(Hash,q)%mod;
            }
            printf("%lld\n",ans);
        }
    }
    return 0;
}
/*
Hash表
暴力模拟蚯蚓队伍的合并和分离
*/

 

posted on 2022-02-28 12:48  St_John  阅读(22)  评论(0编辑  收藏  举报