LOJ#2303. 「NOI2017」蚯蚓排队 hash+链表

正常来说,单次操作的复杂度是 $O(k^2)$,然后整体复杂度是 $O(nk^2)$.   

但是我们发现每次合并两个蚯蚓的复杂度的极限是 $O( min(size_{min},50) \times 50)$. 

然后根据启发式合并的复杂度分析,即使要求遍历完 $size_{min}$,复杂度最高也就是 $O(n \log n k)$.   

这个的极限也就是 $O(10^8)$ 左右,再加上跑不满那个 $O(\log n)$,实际运行速度比较快.   

存储哈希值和合并蚯蚓用的都是链表.   

可以开两个模数,一个小于 $10^7$,一个是 $998244353$,速度应该比 $map$ 之类的快一点.  

code:  

#include <set> 
#include <map>
#include <cstdio> 
#include <cstring>
#include <algorithm> 
#define N 200009 
#define ll long long     
#define MA 9999071 
#define MB 998244353 
#define setIO(s) freopen(s".in","r",stdin) 
using namespace std;   
const int A=233;  
const int B=2333;   
int n,m,edges,cnt;  
int ST[N],ED[N],SIZE[N];   
int BA[200000],BB[200000];
int hd[MA+233],nex[N*100];   
int val[N*100],si[N*100];  
char str[10000008];  
int seqa[10000008]; 
int seqb[10000008];    
struct data {
    int v,l,r;     
}a[N];  
int find(int x,int y) {
    ++cnt;  
    for(int i=hd[x];i;i=nex[i]) {
        if(val[i]==y) return 1;  
    }
    return 0; 
}
void upd(int x,int y,int d) {
    ++cnt; 
    for(int i=hd[x];i;i=nex[i]) {
        ++cnt;  
        if(val[i]==y) {
            si[i]+=d;   
            return;   
        }
    }
}
int query(int x,int y) {
    ++cnt; 
    for(int i=hd[x];i;i=nex[i]) {
        if(val[i]==y) return si[i];   
    }  
    return 0; 
}
void ins(int x,int y) {
    ++cnt; 
    if(find(x,y)) {
        upd(x,y,1);  
    }    
    else {
        nex[++edges]=hd[x];   
        hd[x]=edges,val[edges]=y,si[edges]=1;   
    }
}
void del(int x,int y) {
    upd(x,y,-1);  
}
void init() {
    BA[0]=BB[0]=1;  
    for(int i=1;i<2000;++i) {
        BA[i]=(ll)BA[i-1]*A%MA;   
        BB[i]=(ll)BB[i-1]*B%MB;  
    }
}             
void merge(int x,int y) {
    x=ST[x];    
    int ex=ED[x],ey=ED[y];   
    int len=1,ha=0,hb=0;   
    for(int i=ex;len<=50&&i;i=a[i].l) {
        ha=(ll)(ha+(ll)a[i].v*BA[len]%MA)%MA;    
        hb=(ll)(hb+(ll)a[i].v*BB[len]%MB)%MB;       
        int hta=ha;  
        int htb=hb;  
        for(int j=y,p=len+1;j&&p<=50;j=a[j].r) {
            hta=(ll)((ll)hta*A%MA+(ll)a[j].v*A%MA)%MA;   
            htb=(ll)((ll)htb*B%MB+(ll)a[j].v*B%MB)%MB;        
            ins(hta,htb);  
            ++p;  
        }   
        ++len;    
    }
    a[ex].r=y;  
    a[y].l=ex;    
    ST[ED[y]]=x;    
    ED[x]=ED[y];         
} 
void split(int x) {
    int y=a[x].r;    
    int ra=rand(),sx,ex=x,sy=y,ey;
    if(ra&1) { 
        for(ey=y;a[ey].r;ey=a[ey].r);     
        sx=ST[ey];  
    }
    else { 
        for(sx=x;a[sx].l;sx=a[sx].l);   
        ey=ED[sx];
    }   
    int len=1,ha=0,hb=0;   
    for(int i=ex;len<=50&&i;i=a[i].l) {
        ha=(ll)(ha+(ll)a[i].v*BA[len]%MA)%MA;    
        hb=(ll)(hb+(ll)a[i].v*BB[len]%MB)%MB;       
        int hta=ha;  
        int htb=hb;  
        for(int j=y,p=len+1;j&&p<=50;j=a[j].r) {
            ++cnt;   
            hta=(ll)((ll)hta*A%MA+(ll)a[j].v*A%MA)%MA;   
            htb=(ll)((ll)htb*B%MB+(ll)a[j].v*B%MB)%MB;        
            del(hta,htb);  
            ++p;  
        }     
        ++len;    
    } 
    a[x].r=0;   
    a[y].l=0;      
    ED[sx]=x;      
    ST[x]=sx,ED[x]=x;    
    ST[ey]=y;   
    ED[y]=ey,ST[y]=y;             
}
int main() {
    // setIO("input");     
    scanf("%d%d",&n,&m);   
    init();   
    for(int i=1;i<=n;++i) {
        scanf("%d",&a[i].v);   
        ED[i]=ST[i]=i,SIZE[i]=1;  
        a[i].l=a[i].r=0;  
        ins((ll)a[i].v*A%MA,(ll)a[i].v*B%MB);    
    }  
    int x,y,z;   
    for(int T=1;T<=m;++T) {
        int op;  
        scanf("%d",&op);  
        if(op==1) {
            scanf("%d%d",&x,&y);    
            merge(x,y);  
        }
        if(op==2) { 
            scanf("%d",&x); 
            split(x);    
        }
        if(op==3) {    
            int k,len;
            scanf("%s%d",str+1,&k);  
            len=strlen(str+1);    
            seqa[0]=seqb[0]=0;        
            for(int i=1;i<=len;++i) {
                seqa[i]=(ll)((ll)seqa[i-1]*A%MA+(ll)(str[i]-'0')*A%MA)%MA;   
                seqb[i]=(ll)((ll)seqb[i-1]*B%MB+(ll)(str[i]-'0')*B%MB)%MB;    
            }
            int ans=1;   
            for(int i=k;i<=len;++i) {
                int ca=(ll)(seqa[i]-(ll)seqa[i-k]*BA[k]%MA+MA)%MA;   
                int cb=(ll)(seqb[i]-(ll)seqb[i-k]*BB[k]%MB+MB)%MB;    
                ans=(ll)ans*query(ca,cb)%998244353;   
            }
            printf("%d\n",ans);  
        }         
    } 
    return 0;
}

  

posted @ 2020-07-27 07:51  EM-LGH  阅读(142)  评论(0编辑  收藏  举报