zoukankan      html  css  js  c++  java
  • LOJ#2303. 「NOI2017」蚯蚓排队 hash+链表

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

    但是我们发现每次合并两个蚯蚓的复杂度的极限是 $O( min(size_{min},50) imes 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
    ",ans);  
            }         
        } 
        return 0;
    }
    

      

  • 相关阅读:
    [NOI2010] 能量采集 (数学)
    mysql双主操作记录
    linux查看版本
    netty
    idea修改文件,target目录对应的文件消失
    oracle11g的分区(range、list)索引测试
    There is a cycle in the hierarchy解决办法
    git学习转廖雪峰
    解决SVN Cleanup错误: Failed to run the WC DB work queue associated with
    nginx之 proxy_pass
  • 原文地址:https://www.cnblogs.com/guangheli/p/13383471.html
Copyright © 2011-2022 走看看