BZOJ4943 NOI2017蚯蚓排队(哈希+链表)

  能看懂题就能想到正解。维护所有长度不超过k的数字串的哈希值即可,用链表维护一下蚯蚓间连接情况。由于这样的数字串至多只有nk个,计算哈希值的总复杂度为O(nk),而分裂的复杂度为O(ck^2),询问复杂度为O(Σ|s|)。于是总复杂度为O(nk+ck^2+Σ|s|)。

  手写哈希注意插入元素时考虑清楚,如果没有哈希冲突不需要更新哈希使用的链表,所以特判一下。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
int read()
{
    int x=0;char c=getchar();
    while (c<'0'||c>'9') c=getchar();
    while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x;
}
#define N 200010
#define S 10000010
#define K 50
#define P 19260817
#define MOD 998244353
#define G 7
#define ul unsigned long long 
int n,m,POW[K+1][10];
struct data{int x,pre,nxt;
}a[N];
int ch[S];
int map[P+10],cnt[P+10],nxt[P+10];
ul value[P+10],POWv[K+1][10];
void ins(int x,ul v)
{
    if (!map[x]) map[x]=1,value[x]=v,cnt[x]=1;
    else
    {
        int t;
        while (map[x]&&value[x]!=v) t=x,x=nxt[x];
        if (map[x]) cnt[x]++;
        else map[x]=1,value[x]=v,cnt[x]=1,nxt[t]=x;
    }
}
void del(int x,ul v)
{
    while (value[x]!=v) x=nxt[x];
    cnt[x]--;
}
int query(int x,ul v)
{
    while (map[x]&&value[x]!=v) x=nxt[x];
    return cnt[x];
}
int main()
{
    n=read(),m=read();
    for (int i=0;i<P-1;i++) nxt[i]=i+1;nxt[P-1]=0;
    for (int j=1;j<=9;j++)
    {
        POW[0][j]=j;for (int i=1;i<=K;i++) POW[i][j]=POW[i-1][j]*G%P;
        POWv[0][j]=j;for (int i=1;i<=K;i++) POWv[i][j]=POWv[i-1][j]*G;
    }
    for (int i=1;i<=n;i++) a[i].x=read(),ins(a[i].x,a[i].x);
    while (m--)
    {
        int op=read();
        switch(op)
        {
            case 1:
            {
                int x=read(),y=read();
                a[x].nxt=y,a[y].pre=x;
                for (int l=1,h=x;h&&l<K;h=a[h].pre,l++)
                {
                    int hash=0;ul hashv=0;
                    for (int i=1,t=h;i<=l;t=a[t].nxt,i++)
                    hash=(hash*G+a[t].x)%P,hashv=hashv*G+a[t].x;
                    for (int i=l+1,t=y;t&&i<=K;t=a[t].nxt,i++)
                    {
                        hash=(hash*G+a[t].x)%P,hashv=hashv*G+a[t].x;
                        ins(hash,hashv);
                    }
                }
                break;
            }
            case 2:
            {
                int x=read(),y=a[x].nxt;
                for (int l=1,h=x;h&&l<K;h=a[h].pre,l++)
                {
                    int hash=0;ul hashv=0;
                    for (int i=1,t=h;i<=l;t=a[t].nxt,i++)
                    hash=(hash*G+a[t].x)%P,hashv=hashv*G+a[t].x;
                    for (int i=l+1,t=y;t&&i<=K;t=a[t].nxt,i++)
                    {
                        hash=(hash*G+a[t].x)%P,hashv=hashv*G+a[t].x;
                        del(hash,hashv);
                    }
                }
                a[x].nxt=0;a[y].pre=0;
                break;
            }
            case 3:
            {
                char c=getchar();int l=0;
                while (c<'0'||c>'9') c=getchar();
                while (c>='0'&&c<='9') ch[++l]=c^48,c=getchar();
                int k=read();
                int hash=0;ul hashv=0;
                for (int i=1;i<k;i++) 
                hash=(hash*G+ch[i])%P,hashv=hashv*G+ch[i];
                int ans=1;
                for (int i=k;i<=l;i++)
                {
                    hash=(hash*G+ch[i]-POW[k][ch[i-k]]+P)%P,
                    hashv=hashv*G+ch[i]-POWv[k][ch[i-k]];
                    ans=1ll*ans*query(hash,hashv)%MOD;
                }
                printf("%d\n",ans);
            }    
        }
    }
    return 0;
}

 

posted @ 2018-07-30 21:55  Gloid  阅读(205)  评论(0编辑  收藏  举报