打字機上只有28個按鍵,分別印有26個小寫英文本母和』b』、'p』兩個字母。經阿狸研究發現,這個打字機是這樣工作的:
·輸入小寫字母,打字機的乙個凹槽中會加入這個字母(這個字母加在凹槽的最後)。
·按一下印有』b』的按鍵,打字機凹槽中最後乙個字母會消失。
·按一下印有』p』的按鍵,打字機會在紙上列印出凹槽中現有的所有字母並換行,但凹槽中的字母不會消失。
例如,阿狸輸入apapbbp,紙上被列印的字元如下:
a aa ab 我們把紙上列印出來的字串從1開始順序編號,一直到n。打字機有乙個非常有趣的功能,在打字機中暗藏乙個帶數字的小鍵盤,在小鍵盤上輸入兩個數(x,y)(其中1≤x,y≤n),打字機會顯示第x個列印的字串在第y個列印的字串**現了多少次。
仔細想想,y中有多少個x,不就是求y的某個節點往上跳fail能不能到達x,因為每個節點的fail一定最多只有一條,所有我們完全可以反向建邊,建出fail樹,那麼我們的問題不就是求x往下能到達多少個y的節點,那這就不是相當於求子樹和了嗎?
再想想,如果把所有y的節點全部賦乙個權值1,那麼不就是求x的最後乙個節點的子樹和嗎?
這樣交上去,又t,真是毒瘤…
那麼我們還能怎麼優化呢?我們每次求子樹和的時候都是暴力求和,時間複雜度確實過不了,但沒關係,求子樹和,我們完全可以用線段樹或者樹狀陣列優化!想想將樹上的點按照dfs序打上標號後,乙個樹的子樹和就相當於被降維打擊了,完全可以看成乙個陣列,這樣就可以簡單的套模板求和啦!我們只需要每次在b操作時,將該點的權值-1,移動root到它的父節點。每次訪問到乙個結束的節點時,一定是有且僅有這個串的節點被標記,這樣就能回答關於這個串的相關詢問啦!
具體細節見**!
由於本蒟蒻線段樹容易寫崩掉,所以選擇了好寫的樹狀陣列。
#include
using
namespace std;
const
int maxn =
1e5+50;
struct trie}}
void
build()
}}}void
dfs(
int u)
}int
lowbit
(int x)
//簡單好寫的樹狀陣列
void
add(
int x,
int val)
intquery
(int x)
void
solve()
}else
if(s[i]
=='b'
)else}}
void
work()
insert()
;build()
;dfs(0
);solve()
;for
(int i=
1;i<=m;i++
)printf
("%d\n"
,ans[i]);
}}automaton;
intmain()
P2414 NOI2011 阿狸的打字機
傳送門 先想想暴力怎麼搞 搞乙個ac自動機 對每個詢問 x,y 把 y 暴力向下匹配 每個點都暴力跳fail 看看x出現了幾次 稍微優化一波 因為有多組詢問 考慮離線 可以把同一組的 y 一起來計算 還是把 y 暴力匹配 看看所有的x 出現了幾次 再來一波優化 考慮什麼時候 x 的出現次數會增加 顯...
P2414 NOI2011 阿狸的打字機
p2414 noi2011 阿狸的打字機 顯然跟處理字串有關,但具體用什麼呢?一次列印有可能會列印之前重複過的,當然是 trie 之後查詢作為子串出現過幾次,看看前面的 trie 當然用 trie 圖了 先考慮暴力,y 所在串的每個字元跳 fail 是否能到 x 的末尾 在 parents 樹尤拉序...
NOI2011 JZOJ2784 阿狸的打字機
有乙個快取槽,設計乙個程式維護下面三個操作 i nser tc 在快取槽末尾插入小寫字元c pri nt 將快取所有字元連線輸出為字串 d elet e 刪除快取槽最後乙個字元 操作總共有 n 個。在所有操作結束之後,要支援 m個詢問。每個詢問都是查詢第 x 次輸出的字串在第 y次輸出的字串中出現了...