洛谷 P2336 [SCOI2012]喵星球上的點名 解題報告
阿新 • • 發佈:2019-01-10
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