zoukankan      html  css  js  c++  java
  • [SCOI2012]喵星球上的点名

    题目描述

    a180285 幸运地被选做了地球到喵星球的留学生。他发现喵星人在上课前的点名现象非常有趣。

    假设课堂上有 N 个喵星人,每个喵星人的名字由姓和名构成。喵星球上的老师会选择M 个串来点名,每次读出一个串的时候,如果这个串是一个喵星人的姓或名的子串,那么这个喵星人就必须答到。

    然而,由于喵星人的字码过于古怪,以至于不能用 ASCII 码来表示。为了方便描述,a180285 决定用数串来表示喵星人的名字。

    现在你能帮助 a180285 统计每次点名的时候有多少喵星人答到,以及 M 次点名结束后每个喵星人答到多少次吗?

    输入输出格式

    输入格式:

    现在定义喵星球上的字符串给定方法:

    先给出一个正整数 L ,表示字符串的长度,接下来L个整数表示字符串的每个字符。

    输入的第一行是两个整数 N 和 M。

    接下来有 N 行, 每行包含第 i 个喵星人的姓和名两个串。 姓和名都是标准的喵星球上的字符串。

    接下来有 M 行,每行包含一个喵星球上的字符串,表示老师点名的串。

    输出格式:

    对于每个老师点名的串输出有多少个喵星人应该答到。

    然后在最后一行输出每个喵星人被点到多少次。

     ~~~~~~~~~~~~~~~~~~

    某谷恶意加强数据。

    首先吐槽卡trie图。字符集太大了,trie图会T得很厉害,建个图就超时了。

    别人用map,然而我不喜欢迭代器,就用了treap维护儿子。

    代码:

    #include<ctime>
    #include<queue>
    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    using namespace std;
    #define N 200050
    #define M 200050
    inline int rd()
    {
        int f=1,c=0;char ch = getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){c=(c<<3)+(c<<1)+ch-'0';ch=getchar();}
        return f*c;
    }
    int n,m,tot;
    int ls[M<<1],rs[M<<1],rnd[M<<1],w[M<<1];
    struct Treap
    {
        int rt;
        void lturn(int &x)
        {
            int y = rs[x];
            rs[x]=ls[y],ls[y]=x;
            x=y;
        }
        void rturn(int &x)
        {
            int y = ls[x];
            ls[x]=rs[y],rs[y]=x;
            x=y;
        }
        int query(int k,int x)
        {
            if(w[k]==x)return k;
            if(!k)return 0;
            return query(w[k]<x?rs[k]:ls[k],x);
        }
        void insert(int &k,int x)
        {
            if(!k)
            {
                k=++tot;
                rnd[k]=rand();
                w[k]=x;
                return ;
            }else if(w[k]<x)
            {
                insert(rs[k],x);
                if(rnd[rs[k]]<rnd[k])lturn(k);
            }else
            {
                insert(ls[k],x);
                if(rnd[ls[k]]<rnd[k])rturn(k);
            }
        }
    };
    int lin[M],sum;
    struct nam
    {
        int len1,len2;
        int l1,r1,l2,r2;
    }q[N];
    int hed[M<<1],cntt;
    struct Trie
    {
        Treap ch;
    //    vector<int>vv;
        int f,ct;
    }tr[M<<1];
    struct EG
    {
        int to,nxt;
    }e[M];
    void ae(int f,int t)
    {
        e[++cntt].to = t;
        e[cntt].nxt = hed[f];
        hed[f] = cntt;
    }
    bool vis1[M],vis2[M];
    void init()
    {
        for(int i=1;i<=tot;i++)
            vis1[i]=0;
        for(int i=1;i<=n;i++)
            vis2[i]=0;
    }
    void acmach()
    {
        queue<int>q,c;
        q.push(0);
        while(!q.empty())
        {
            int u = q.front();
            q.pop();
            if(!tr[u].ch.rt)continue;
            c.push(tr[u].ch.rt);
            while(!c.empty())
            {
                int v = c.front();
                c.pop();
                if(ls[v])c.push(ls[v]);
                if(rs[v])c.push(rs[v]);
                int to = tr[u].f;
                while(to&&!tr[to].ch.query(tr[to].ch.rt,w[v]))to=tr[to].f;
                int hhh=tr[to].ch.query(tr[to].ch.rt,w[v]);
                if(hhh&&u)to=hhh;
                tr[v].f = to;
                q.push(v);
            }
        }
    }
    int as1[N],as2[M];
    int deal(int u)
    {
        int ret = 0;
        while(!vis1[u])
        {
            for(int j=hed[u];j;j=e[j].nxt)
            {
                int i = e[j].to;
                vis2[i]=1;
                as2[i]++;
            }
            ret+=tr[u].ct;
            vis1[u]=1;
            u = tr[u].f;
        }
        return ret;
    }
    int main()
    {
        srand(time(NULL));
        n=rd(),m=rd();
        int u,c,v;
        for(int i=1;i<=n;i++)
        {
            q[i].len1=rd();
            q[i].l1 = sum+1,q[i].r1 = sum+q[i].len1;
            for(int j=q[i].l1;j<=q[i].r1;j++)lin[j]=rd();
            sum+=q[i].len1;
            q[i].len2=rd();
            q[i].l2 = sum+1,q[i].r2 = sum+q[i].len2;
            for(int j=q[i].l2;j<=q[i].r2;j++)lin[j]=rd();
            sum+=q[i].len2;
        }
        for(int i=1;i<=m;i++)
        {
            c=rd();
            u=0;
            for(int j=1;j<=c;j++)
            {
                v=rd();
                if(!tr[u].ch.query(tr[u].ch.rt,v))tr[u].ch.insert(tr[u].ch.rt,v);
                u = tr[u].ch.query(tr[u].ch.rt,v);
            }
    //        tr[u].vv.push_back(i);
            ae(u,i);
            tr[u].ct++;
        }
        acmach();
        vis1[0]=1;
        for(int i=1;i<=n;i++)
        {
            init();
            u=0;
            for(int j=q[i].l1;j<=q[i].r1;j++)
            {
                c = lin[j];
                while(u&&!tr[u].ch.query(tr[u].ch.rt,c))u=tr[u].f;
                int hhh = tr[u].ch.query(tr[u].ch.rt,c);
                if(hhh)u=hhh;
                as1[i]+=deal(u);
            }
            u=0;
            for(int j=q[i].l2;j<=q[i].r2;j++)
            {
                c = lin[j];
                while(u&&!tr[u].ch.query(tr[u].ch.rt,c))u=tr[u].f;
                int hhh = tr[u].ch.query(tr[u].ch.rt,c);
                if(hhh)u=hhh;
                as1[i]+=deal(u);
            }
        }
        for(int i=1;i<=m;i++)printf("%d
    ",as2[i]);
        for(int i=1;i<=n;i++)printf("%d ",as1[i]);
        printf("
    ");
        return 0;
    }

    后来才知道AC自动机并不是正解,只是当时数据水能过……

    现在讲一下后缀自动机做法(貌似也不是正解

    对于姓名串我们用广义后缀自动机存上,然后离线处理点名达到数。

    处理方法依然为树状数组之HH的项链。

    这一段复杂度为O(n logn *map的log);

    对于答道次数,我们可以将姓名串放在后缀自动机上跑一遍,每到一个节点就沿着pre指针跳到第一个到过的地方。

    复杂度好像O(n)?

    代码:

    #include<map>
    #include<vector>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define N 50050
    #define M 100050
    int n,m;
    struct Point
    {
        int pre,len;
        map<int,int>trs;
        vector<int>ve;
    }p[2*M];
    struct EG
    {
        int to,nxt;
    }e[2*M];
    int hed[2*M],cnt;
    void ae(int f,int t)
    {
        e[++cnt].to = t;
        e[cnt].nxt = hed[f];
        hed[f] = cnt;
    }
    int tin[2*M],tout[2*M],tim,pla[2*M],v[2*M];
    struct SAM
    {
        int tot,las;
        SAM(){tot=las=1;}
        void res(){las=1;}
        void insert(int c,int k)
        {
            int np,nq,lp,lq;
            np=++tot;
            p[np].len = p[las].len+1;
            for(lp = las;lp&&p[lp].trs.find(c)==p[lp].trs.end();lp=p[lp].pre)
                p[lp].trs[c] = np;
            if(!lp)p[np].pre = 1;
            else
            {
                lq = p[lp].trs[c];
                if(p[lq].len==p[lp].len+1)p[np].pre = lq;
                else
                {
                    nq=++tot;
                    p[nq] = p[lq];
                    p[nq].len = p[lp].len+1;
                    p[lq].pre = p[np].pre = nq;
                    while(p[lp].trs[c]==lq)
                    {
                        p[lp].trs[c]=nq;
                        lp = p[lp].pre;
                    }
                }
            }
            las = np;
            p[np].ve.push_back(k);
        }
        void dfs(int u)
        {
            tin[u]=++tim;pla[tim]=u;
            for(int j=hed[u];j;j=e[j].nxt)dfs(e[j].to);
            tout[u]=tim;
        }
        void build()
        {
            for(int i=2;i<=tot;i++)
                ae(p[i].pre,i);
            dfs(1);
        }
    }sam;
    vector<int>nam[N][2];
    int ct,ans[M];
    int las[N];
    struct Que
    {
        int l,r,id;
    }que[M];
    bool cmp(Que a,Que b)
    {
        return a.r<b.r;
    }
    int f[2*M];
    void up(int x,int d)
    {
        if(!x)return ;
        while(x<=200000)f[x]+=d,x+=(x&(-x));
    }
    int down(int x)
    {
        if(!x)return 0;
        int ret = 0;
        while(x)ret+=f[x],x-=(x&(-x));
        return ret;
    }
    int vis[2*M];
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int c,x,i=1;i<=n;i++)
        {
            scanf("%d",&x);
            sam.res();
            while(x--)
            {
                scanf("%d",&c);
                nam[i][0].push_back(c);
                sam.insert(c,i);
            }
            scanf("%d",&x);
            sam.res();
            while(x--)
            {
                scanf("%d",&c);
                nam[i][1].push_back(c);
                sam.insert(c,i);
            }
        }
        sam.build();
        for(int c,x,i=1;i<=m;i++)
        {
            scanf("%d",&x);
            int u=1;
            while(x--)
            {
                scanf("%d",&c);
                if(p[u].trs.find(c)==p[u].trs.end()){u=0;}
                u=p[u].trs[c];
            }
            if(u)
            {
                ct++;
                que[ct].l = tin[u];
                que[ct].r = tout[u];
                que[ct].id = i;
                v[u]++;
            }
        }
        sort(que+1,que+1+ct,cmp);
        for(int k=1,i=1;i<=tim;i++)
        {
            for(int j=0;j<p[pla[i]].ve.size();j++)
            {
                up(i,1);
                up(las[p[pla[i]].ve[j]],-1);
                las[p[pla[i]].ve[j]]=i;
            }
            int tmp = down(i);
            for(;que[k].r==i;k++)
                ans[que[k].id] = tmp - down(que[k].l-1);
        }
        for(int i=1;i<=m;i++)
            printf("%d
    ",ans[i]);
        for(int i=1;i<=n;i++)
        {
            int c = 0,u=1;
            for(int j=0;j<nam[i][0].size();j++)
            {
                u = p[u].trs[nam[i][0][j]];
                int tmp = u;
                while(tmp!=1&&vis[tmp]<i)
                {
                    vis[tmp]=i;
                    c+=v[tmp];
                    tmp=p[tmp].pre;
                }
            }
            u=1;
            for(int j=0;j<nam[i][1].size();j++)
            {
                u = p[u].trs[nam[i][1][j]];
                int tmp = u;
                while(tmp!=1&&vis[tmp]<i)
                {
                    vis[tmp]=i;
                    c+=v[tmp];
                    tmp=p[tmp].pre;
                }
            }
            printf("%d ",c);
        }
        printf("
    ");
        return 0;
    }
  • 相关阅读:
    网络基础之网络协议篇
    JVM-07-执行引擎
    JVM-06-对象实例化、内存布局、访问定位以及直接内存
    JVM-05-方法区
    JVM-04-堆
    JVM-03-本地方法接口和本地方法栈
    JVM-02-程序计数器 虚拟机栈
    JVM-01-类加载子系统
    JVM-00-引言
    swagger
  • 原文地址:https://www.cnblogs.com/LiGuanlin1124/p/9689720.html
Copyright © 2011-2022 走看看