• [BZOJ4943][NOI2017]蚯蚓


    bzoj
    luogu
    uoj

    sol

    用链表维护蚯蚓的相对顺序。
    发现每次询问的(kle50),所以在每次链表的合并与分离时,暴力找前后(50)个位置,然后(O(k^2))地塞进(Hash Table)或者从(Hash Table)里面删除。
    因为分离操作最多(10^3)次,所以合并操作最多(n+999)次,复杂度显然会是对的。

    code

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    int gi(){
    	int x=0,w=1;char ch=getchar();
    	while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    	if (ch=='-') w=0,ch=getchar();
    	while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    	return w?x:-x;
    }
    #define ull unsigned long long
    const int N = 2e5+5;
    const int base = 20020415;
    const int K = 51;
    const int mod = 998244353;
    int n,m,a[N],pre[N],nxt[N],f[N];ull pw[N],g[N];char s[N*50];
    struct edge{ull v;int nxt,w;}E[N*99];int head[4194304],cnt;
    void add(ull val,int op){
    	int u=val&4194303,e=head[u];
    	for (;e;e=E[e].nxt) if (E[e].v==val) {E[e].w+=op;return;}
    	E[e=++cnt]=(edge){val,head[u],op};head[u]=e;
    }
    int query(ull val){
    	int u=val&4194303,e=head[u];
    	for (;e;e=E[e].nxt) if (E[e].v==val) return E[e].w;
    	return 0;
    }
    void merge(){
    	int x=gi(),y=gi(),l=K,r=K-1;
    	for (int i=x;i&&l>1;i=pre[i]) f[--l]=a[i];
    	for (int i=y;i&&r<K*2;i=nxt[i]) f[++r]=a[i];
    	for (int i=1;i<=r;++i) g[i]=g[i-1]*base+f[i];
    	for (int i=l;i<K;++i)
    		for (int j=K;j<=min(r,i+49);++j)
    			add(g[j]-g[i-1]*pw[j-i+1],1);
    	nxt[x]=y;pre[y]=x;
    }
    void split(){
    	int x=gi(),y=nxt[x],l=K,r=K-1;
    	for (int i=x;i&&l>1;i=pre[i]) f[--l]=a[i];
    	for (int i=y;i&&r<K*2;i=nxt[i]) f[++r]=a[i];
    	for (int i=1;i<=r;++i) g[i]=g[i-1]*base+f[i];
    	for (int i=l;i<K;++i)
    		for (int j=K;j<=min(r,i+49);++j)
    			add(g[j]-g[i-1]*pw[j-i+1],-1);
    	nxt[x]=pre[y]=0;
    }
    int query(){
    	scanf("%s",s+1);int k=gi(),len=strlen(s+1);ull val=0;
    	for (int i=1;i<=k;++i) val=val*base+s[i];
    	int res=query(val);
    	for (int i=k+1;i<=len;++i){
    		val=val*base+s[i];
    		val-=s[i-k]*pw[k];
    		res=1ll*res*query(val)%mod;
    	}
    	return res;
    }
    int main(){
    	n=gi();m=gi();pw[0]=1;
    	for (int i=1;i<N;++i) pw[i]=pw[i-1]*base;
    	for (int i=1;i<=n;++i) add(a[i]=gi()+'0',1);
    	while (m--){
    		int op=gi();
    		if (op==1) merge();
    		else if (op==2) split();
    		else printf("%d
    ",query());
    	}
    	return 0;
    }
    
  • 相关阅读:
    『软件介绍』SQLServer2008 基本操作
    PCA的数学原理
    PCA的数学原理
    Oracle数据处理
    UVa 11995
    Unreal Engine 4 C++ 为编辑器中Actor创建自己定义图标
    codecombat之边远地区的森林1-11关及地牢38关代码分享
    初识ecside
    how tomcat works读书笔记 七 日志记录器
    HDU 1754(线段树区间最值)
  • 原文地址:https://www.cnblogs.com/zhoushuyu/p/9255640.html
Copyright © 2020-2023  润新知