喵星球上的點名(字尾自動機 dfs序 莫隊)

2021-09-28 06:58:04 字數 2778 閱讀 3148

一道據傳言有多種解法的題(不過大多是因為資料太弱過的)。先用ac自動機搞了一上午,無果;看了題解,字尾自動機+莫隊?正好是我最喜歡的演算法之一+正在學習的演算法,就這個了!然後由於廣義自動機的las

tlast

last

標記有個地方忘了初始化。。。然後在大物課上調了三節課,洛谷一頁都是我,hhh

題意

有n

nn個同學,名字包含姓和名;然後老師要點m

mm次名,某次點名若是某個同學的姓或者名的子串,則這位同學要答到。求:

每次點名會有多少同學答到

m

mm次點名後每位同學分別會答到多少次

思路字尾自動機+dfs

dfsdf

s序+莫隊

由於涉及多字串,當然是用廣義字尾自動機搞呀(也可以在字串之間插入不涉及的數字,並且用map

mapma

p存轉移邊);同時記得在建字尾自動機時給每個節點表明是屬於哪個人的,畢竟後面要分別統計每個人的答到次數;還有虛點的問題,這裡的處理其實比較隨意,你既可以當做是當前同學的,也可以當做是之前同學的,甚至可以當做乙個不會出現的同學的(比如預設為0

00),這點是非常有趣的。

詢問中需要知道每次點名會有多少人答到,顯然可以直接在字尾自動機上跑這個點名的字串,找到那個節點後,屬於這個節點的整棵par

en

tparent

parent

t re

etree

tree

子樹的同學都是要答到的。

這時我們容易想到處理出par

en

tparent

parent

t re

etree

tree

的d fs

dfsdf

s序,這樣屬於某個節點的整棵子樹在dfs

dfsdf

s序上都是連續的一段,當我們想要知道裡面有多少個不同的同學的姓名時,也就是詢問區間不同種類數字個數!就可以直接莫隊處理啦(也可以像hh的項鍊那樣用樹狀陣列處理啦)。

至此,第乙個問題就輕鬆解決了,那麼第二問呢?第二個問題可以等效為某個節點被多少詢問區間所包含!注意到在使用莫隊的過程中,每個節點總是在不斷地進入,出去。那麼,在進入之後,出來之前發生了什麼呢?顯然這個節點(同學)在不斷地貢獻答案,也就是他在這段時間內一直被包含!因此,在端點移動過程中,每次有新的未出現的節點進入區間,就記錄這個節點的進入時間,當他出去的時候,就統計答案。這樣,每個同學被點到的次數就被分成了多段連續的時間,加在一起就是總的次數!

補充:第二問同樣可以用樹狀陣列處理:將區間放在樹狀陣列上,每當到達區間左端點時,bit

[l]+

1bit[l]+1

bit[l]

+1,到達區間右端點時,bit

[l]−

1bit[l]-1

bit[l]

−1;沒當到達某個人的姓名時(兩部分),對於每個人的兩個字串,靠左邊的統計答案為ans

=qsu

m(po

s1

)ans=qsum(pos1)

ans=qs

um(p

os1)

,靠右邊的統計為ans

+=qs

um(p

os2)

−qsu

m(po

s1

)ans+=qsum(pos2)-qsum(pos1)

ans+=q

sum(

pos2

)−qs

um(p

os1)

;這樣的處理就可以知道這個人總共被覆蓋多少次啦!

妙哉!!!

#include "bits/stdc++.h"

#define hhh printf("hhh\n")

#define see(x) (cerr<<(#x)<<'='<<(x)inline int read()

const int maxn = 4e5+10;

const int inf = 0x3f3f3f3f;

const int mod = 1e9+7;

const double eps = 1e-7;

int n, m;

mapch[maxn];

int len[maxn], fa[maxn], belong[maxn], last=1, sz=1;

int head[maxn], to[maxn], nxt[maxn], tot;

int siz[maxn], id[maxn], rk[maxn], dfn, vis[maxn], pre[maxn];

int cur, cntq, ans1[maxn], ans2[maxn], block;

inline void add_edge(int u, int v)

struct q

while(rq[i].r)

ans1[q[i].id]=cur;

}for(int i=1; i<=n; ++i) if(vis[i]) ans2[i]+=cntq+1-pre[i]; //別忘了有些同學還沒有離開區間呀

for(int i=1; i<=m; ++i) printf("%d\n", ans1[i]);

for(int i=1; i<=n; ++i) printf("%d%c", ans2[i], " \n"[i==n]);

}

喵星球上的點名

a180285幸運地被選做了地球到喵星球的留學生。他發現喵星人在上課前的點名現象非常有趣。假設課堂上有n個喵星人,每個喵星人的名字由姓和名構成。喵星球上的老師會選擇m個串來點名,每次讀出乙個串的時候,如果這個串是乙個喵星人的姓或名的子串,那麼這個喵星人就必須答到。然而,由於喵星人的字碼過於古怪,以至...

bzoj2754 喵星球上的點名 字尾陣列

好久不寫字尾樹組了 好像以前也就寫過一遍吧 各種奇葩出錯。實際上即使是字尾樹組時間複雜度也是不對的。為o m len 另外ac自動機也可做,時間複雜度還是不對。可能可以用樹上的一些結構來統計保證時間複雜度,但具體沒有想過 首先將姓名和點名串用間隔符連起來跑字尾樹組 sam應該也行,但是後面完全不一樣...

BZOJ 2754 喵星球上的點名(字尾陣列)

題意 給出n個字典串,m個詢問串。輸出每個詢問串出現在多少個字典串中。最後輸出每個字典串中含有多少個詢問串。思路 將所有字典串和所有詢問串連在一起求sa和h陣列。統計時對於每個詢問串,設長度為len,向前向後掃一下h值大於等於len的區間。然後在這個區間中看有多少個字典串,就是這個詢問串的答案,同時...