• 【题解】SP8093 JZPGYZ


    SP8093 JZPGYZ - Sevenk Love Oimaster

    ( ext{Solution:})

    坑人的 spoj 不给数据)傻逼的笔者做到了 CF204E Little Elephant and Strings 才仔细想明白自己为啥子树数颜色错了好久……

    显然,建立好广义 SAM 并且给属于不同串的节点染色之后,就变成了一个 parent 树上的子树数颜色问题。

    那这个问题长得很 HH的项链 啊。考虑把每一个点的子树都求出来,设 (cpos[i]) 表示颜色 (i) 上此出现的 dfs序 是什么。

    由于我们根据 dfs序 把原问题转化到的序列上,所以我们也要保证做的时候 dfs序 单调,而不是点编号。

    然后就是一个简单的数颜色啦:对当前 dfs序,单点 (+1) 并且把上一次出现位置 (-1...) 但愉快写完后发现自己 WA 了,还不能看数据也不知道答案偏大偏小。

    那问题就很玄学了,死活不知道哪里写错。实际上:你颜色都是非负的,但这样处理会把没有颜色的节点当成一种颜色,答案就错了。

    剩下就没啥问题了 一个树状数组的事情罢了。

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    const int N=1e6+10;
    inline int lowbit(int x){return x&(-x);}
    int tr[N];
    namespace SAM{
        int len[N],pa[N],ch[N][26],tag[N];
        int last=1,tot=1,dfn[N],dfstime;
        int pos[N],cpos[N],siz[N],num[N];
        int rk[N],colf[N];
        vector<int>G[N],qr[N];
        void insert(const int &c,const int &col){
            int p=last;
            int np=++tot;
            last=tot;len[np]=len[p]+1;tag[np]=col;
            for(;p&&!ch[p][c];p=pa[p])ch[p][c]=np;
            if(!p)pa[np]=1;
            else{
                int q=ch[p][c];
                if(len[q]==len[p]+1)pa[np]=q;
                else{
                    int nq=++tot;
                    len[nq]=len[p]+1;
                    memcpy(ch[nq],ch[q],sizeof ch[q]);
                    pa[nq]=pa[q];pa[q]=pa[np]=nq;
                    for(;p&&ch[p][c]==q;p=pa[p])ch[p][c]=nq;
                }
            }
        }
        void dfs(int x){
            dfn[x]=++dfstime;siz[x]=1;rk[dfstime]=x;
            colf[dfstime]=tag[x];
            for(auto i:G[x])dfs(i),siz[x]+=siz[i];
        }
        void change(int x,int v){
            while(x<=tot)tr[x]+=v,x+=lowbit(x);
        }
        int query(int x){
            int res=0;
            while(x)res+=tr[x],x-=lowbit(x);
            return res;
        }
        void BuildTree(){
            for(int i=2;i<=tot;++i)G[pa[i]].push_back(i);
            dfs(1);
            for(int i=1;i<=tot;++i)qr[dfn[i]+siz[i]-1].push_back(i);
            for(int i=1;i<=tot;++i){
                if(!cpos[colf[i]])cpos[colf[i]]=i;
                pos[i]=cpos[colf[i]];cpos[colf[i]]=i;
            }
            for(int i=1;i<=tot;++i){
            	if(!colf[i])continue;
                change(i,1);
                if(i!=pos[i])change(pos[i],-1);
                for(auto v:qr[i]){
                    // printf("(%d %d)
    ",i,dfn[v]);
                    num[v]=query(i)-query(dfn[v]-1);
                    // puts("?");
                }
            }
        }
    }
    using namespace SAM;
    int n,m;
    char s[N];
    signed main(){
        scanf("%lld%lld",&n,&m);
        for(int i=1;i<=n;++i){
            scanf("%s",s+1);
            last=1;
            int len=strlen(s+1);
            for(int j=1;j<=len;++j)insert(s[j]-'a',i);
        }
        BuildTree();
        // for(int i=1;i<=tot;++i)cout<<num[i]<<endl;
        for(int i=1;i<=m;++i){
            scanf("%s",s+1);
            int len=strlen(s+1);
            int node=1,fg=0;
            for(int j=1;j<=len&&!fg;++j){
                int v=s[j]-'a';
                if(ch[node][v])node=ch[node][v];
                else{puts("0");fg=1;break;}
            }
            if(!fg)printf("%lld
    ",num[node]);
        }
        return 0;
    }
    
  • 相关阅读:
    [CQOI2005]三角形面积并(计算几何+扫描线)
    第一天
    LA3026 周期 (kmp)
    HDU 1715 大菲波数 (java大数)
    根据身高重建队列(vector)
    K 连续位的最小翻转次数
    724. Find Pivot Index
    Two Sum
    c
    Most Powerful(状压DP水题)
  • 原文地址:https://www.cnblogs.com/h-lka/p/15176467.html
Copyright © 2020-2023  润新知