1. 程式人生 > >洛谷 P2336 [SCOI2012]喵星球上的點名 解題報告

洛谷 P2336 [SCOI2012]喵星球上的點名 解題報告

P2336 [SCOI2012]喵星球上的點名

題目描述

a180285 幸運地被選做了地球到喵星球的留學生。他發現喵星人在上課前的點名現象非常有趣。

假設課堂上有 \(N\) 個喵星人,每個喵星人的名字由姓和名構成。喵星球上的老師會選擇 \(M\) 個串來點名,每次讀出一個串的時候,如果這個串是一個喵星人的姓或名的子串,那麼這個喵星人就必須答到。

然而,由於喵星人的字碼過於古怪,以至於不能用 ASCII 碼來表示。為了方便描述,a180285 決定用數串來表示喵星人的名字。

現在你能幫助 a180285 統計每次點名的時候有多少喵星人答到,以及 \(M\) 次點名結束後每個喵星人答到多少次嗎?

輸入輸出格式

輸入格式:

現在定義喵星球上的字串給定方法:

先給出一個正整數 \(L\) ,表示字串的長度,接下來\(L\)個整數表示字串的每個字元。

輸入的第一行是兩個整數 \(N\)\(M\)

接下來有 \(N\) 行, 每行包含第 \(i\) 個喵星人的姓和名兩個串。 姓和名都是標準的喵星球上的字串。

接下來有 \(M\) 行,每行包含一個喵星球上的字串,表示老師點名的串。

輸出格式:

對於每個老師點名的串輸出有多少個喵星人應該答到。

然後在最後一行輸出每個喵星人被點到多少次。

說明

\(n\le 5\times 10^4,m\le 10^5\),串總長\(\le 10^5\)


先建廣義SAM

發現點名是子樹問題,轉換到dfs序

第一問就是區間求顏色數,第二問是統計每種顏色被多少區間覆蓋。

用莫隊就可以了,在新加入顏色和刪去顏色的時候處理一下就行了。


Code:

#include <cstdio>
#include <cmath>
#include <algorithm>
#include <map>
const int N=2e5+10;
std::map <int,int> ch[N];
int col[N],par[N],len[N],las=1,tot=1,id;
void extend(int c)
{
    int now=++tot,p=las;
    len[now]=len[p]+1,col[now]=id;
    while(p&&!ch[p][c]) ch[p][c]=now,p=par[p];
    if(!p) par[now]=1;
    else
    {
        int x=ch[p][c];
        if(len[x]==len[p]+1) par[now]=x;
        else
        {
            int y=++tot;
            len[y]=len[p]+1,par[y]=par[x],col[y]=id,ch[y]=ch[x];
            while(p&&ch[p][c]==x) ch[p][c]=y,p=par[p];
            par[now]=par[x]=y;
        }
    }
    las=now;
}
int head[N],to[N],Next[N],cnt;
void add(int u,int v)
{
    to[++cnt]=v,Next[cnt]=head[u],head[u]=cnt;
}
int dfn[N],low[N],ha[N],dfsclock,n,m,m_;
void dfs(int now)
{
    ha[dfn[now]=++dfsclock]=now;
    for(int i=head[now];i;i=Next[i]) dfs(to[i]);
    low[now]=dfsclock;
}
struct node
{
    int id,l,r,fi;
    node(){}
    node(int id,int l,int r,int fi){this->id=id,this->l=l,this->r=r,this->fi=fi;}
    bool friend operator <(node a,node b){return a.fi==b.fi?a.l<b.l:a.fi<b.fi;}
}q[N];
int ans[N],sum[N],st[N],tax[N],su;
void add(int p)
{
    int c=col[ha[p]];
    if(!tax[c]) ++su,st[c]=id;
    ++tax[c];
}
void del(int p)
{
    int c=col[ha[p]];
    --tax[c];
    if(!tax[c]) --su,sum[c]+=id-st[c];
}
int main()
{
    scanf("%d%d",&n,&m);
    for(id=1;id<=n;id++)
    {
        int Len;las=1;
        scanf("%d",&Len);
        for(int c,i=1;i<=Len;i++) scanf("%d",&c),extend(c);
        las=1;scanf("%d",&Len);
        for(int c,i=1;i<=Len;i++) scanf("%d",&c),extend(c);
    }
    for(int i=2;i<=tot;i++) add(par[i],i);
    dfs(1);int B=sqrt(dfsclock)+1;
    for(int i=1;i<=m;i++)
    {
        int Len,now=1;
        scanf("%d",&Len);
        for(int c,j=1;j<=Len;j++)
        {
            scanf("%d",&c);
            now=ch[now][c];
        }
        if(now) q[++m_]=node(i,dfn[now],low[now],low[now]/B);
    }
    std::sort(q+1,q+1+m_);
    int l=q[1].l,r=l-1;
    for(id=1;id<=m_;id++)
    {
        while(q[id].l<l) add(--l);
        while(q[id].l>l) del(l++);
        while(q[id].r<r) del(r--);
        while(q[id].r>r) add(++r);
        ans[q[id].id]=su;
    }
    while(l<=r) del(l++);
    for(int i=1;i<=m;i++) printf("%d\n",ans[i]);
    for(int i=1;i<=n;i++) printf("%d ",sum[i]);
    return 0;
}

2019.1.10