zoukankan      html  css  js  c++  java
  • bzoj2780: [Spoj]8093 Sevenk Love Oimaster

    建完sam以后自然而然的就是建后缀树了。

    问题转化成多次询问一棵树(fail树)的子树中有多少不同颜色的节点。

    等于一个序列的一段有多少种不同的颜色

    这是个套路题,离线dfs序+树状数组可解(为什么我看了这么久愣是没看出来呢....)

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    
    int aa[110000];
    struct SAM
    {
        int w[30],dep,fail,col;
    }ch[210000];int cnt,las;
    void insert(int dep,int col,int x)
    {
        int pre=las,now=++cnt;
        ch[now].dep=dep,ch[now].col=col;
        las=now;
        
        while(pre!=0&&ch[pre].w[x]==0)
            ch[pre].w[x]=now, pre=ch[pre].fail;
        if(pre==0)ch[now].fail=1;
        else
        {
            int nxt=ch[pre].w[x];
            if(ch[nxt].dep==ch[pre].dep+1)ch[now].fail=nxt;
            else
            {
                int nnxt=++cnt;
                ch[nnxt]=ch[nxt];
                ch[nnxt].dep=ch[pre].dep+1;
                
                ch[nxt].fail=ch[now].fail=nnxt;
                while(pre!=0&&ch[pre].w[x]==nxt)
                    ch[pre].w[x]=nnxt, pre=ch[pre].fail;
            }
        }
    }
    
    //--------------------------------------SAM---------------------------------------------------
    
    struct node
    {
        int x,y,next;
    }a[210000];int len,last[210000];
    void ins(int x,int y)
    {
        len++;
        a[len].x=x;a[len].y=y;
        a[len].next=last[x];last[x]=len;
    }
    int z,L[210000],R[210000],co[210000];
    void dfs(int x)
    {
        L[x]=++z;co[z]=ch[x].col;
        for(int k=last[x];k;k=a[k].next)
        {
            int y=a[k].y;
            dfs(y);
        }
        R[x]=z;
    }
    void MakeFailTree()
    {
        len=0;memset(last,0,sizeof(last));
        for(int i=2;i<=cnt;i++)ins(ch[i].fail,i);
        z=0,dfs(1);
    }
    
    //-----------------------------------------init----------------------------------------------------
    
    /*
        多次询问一棵树(fail树)的子树中有多少不同颜色的节点。
     == 一个序列的一段有多少种不同的颜色
    */
    int s[210000];
    int lowbit(int x){return x&-x;}
    void change(int x,int k)
    {
        while(x<=cnt+10)
        {
            s[x]+=k;
            x+=lowbit(x);
        }
    }
    int getsum(int x)
    {
        int ret=0;
        while(x>0)
        {
            ret+=s[x];
            x-=lowbit(x);
        }
        return ret;
    }
    
    //-----------------------------------------calc----------------------------------------------------
    
    char ss[110000];
    struct query{int l,r,id;}q[61000];int qlen;
    bool cmp(query q1,query q2){return q1.r<q2.r;} 
    int ec[11000],as[61000];
    int main()
    {
        int n,Q,len;
        scanf("%d%d",&n,&Q);
        cnt=1;
        for(int t=1;t<=n;t++)
        {
            las=1;
            scanf("%s",ss+1);len=strlen(ss+1);
            for(int i=1;i<=len;i++)
                aa[i]=ss[i]-'a'+1, insert(i,t,aa[i]);
        }
        MakeFailTree();
        
        for(int t=1;t<=Q;t++)
        {
            scanf("%s",ss+1);len=strlen(ss+1);
            for(int i=1;i<=len;i++)aa[i]=ss[i]-'a'+1;
            
            int now=1; bool bk=true;
            for(int i=1;i<=len;i++)
            {
                int x=aa[i];
                if(ch[now].w[x]==0){bk=false;break;}
                else now=ch[now].w[x];
            }
            
            if(bk==false)as[t]=0;
            else q[++qlen].l=L[now],q[qlen].r=R[now],q[qlen].id=t;
        }
        
        sort(q+1,q+qlen+1,cmp); int tp=1;
        memset(ec,0,sizeof(ec));
        for(int i=1;i<=cnt;i++)
        {
            if(ec[co[i]]!=0)change(ec[co[i]],-1);
            ec[co[i]]=i,change(i,1);
            
            while(tp<=qlen&&q[tp].r==i)
            {
                as[q[tp].id]=getsum(q[tp].r)-getsum(q[tp].l-1);
                tp++;
            }
        }
        for(int i=1;i<=Q;i++)printf("%d
    ",as[i]);
        
        return 0;
    }

     


    多次询问一棵树(fail树)的子树中有多少不同颜色的节点。 == 一个序列的一段有多少种不同的颜色

  • 相关阅读:
    C# 杨辉三角 下
    C# 自动走迷宫 下
    算法练习之1数字填充 下
    动态添加控件并获取其值
    两个ListBox的互动
    VS2005常用快捷键
    GridView内嵌DropDownList操作
    GridView格式化短日期
    获得客户端ID
    Access数据库 Update 语句的怪现象
  • 原文地址:https://www.cnblogs.com/AKCqhzdy/p/10064922.html
Copyright © 2011-2022 走看看