題目鏈結
題目大意:初始字串為空,首先給定一系列操作序列,有三種操作:
1.在結尾加乙個字元
2.在結尾刪除乙個字元
3.列印當前字串
然後多次詢問第x個列印的字串在第y個列印的字串中出現了幾次
題解:建出trie……
新增乙個字元->新建乙個子節點(若存在在不用新建),進入該子節點
刪除乙個字元->返回到父親節點
列印當前字串->在當前節點標記是第幾個列印串
跑出fail指標
對於ac自動機上的兩個子串u,v(ac自動機上的子串x可以看成是從根節點到節點x連成的乙個字串),u是v的子串等價於u是v某個字首的字尾,而判斷u是x的字尾只需要看x能否沿著fail指標走到u
所以查詢u在v中出現的次數即為查詢根結點到v的路徑中有多少個x,能沿著fail指標走到u
fail指標沒有環 每個節點只有乙個出度 那麼反向之後顯然是一棵樹,x沿著反向fail邊走到的點構成x的子樹
那麼查詢(u,v)時,把root->v的路徑上的點賦值為1,答案可以通過查詢x的子樹和解決,dfs序上單點修改區間求和就可以了
但是不能直接暴力改……需要採用一些方法減少修改次數
離線,按照v排序,這樣就可以根據原來建立ac自動機的順序進行修改了…………只需要進入時+1,離開時-1,查詢時自然root->v的路徑上的每乙個點都是1了
我的收穫:ac自動機~~
#include
using
namespace
std;
const
int n=100015;
int m;
int t,head[n];
int tim,in[n],out[n];
int cnt,pos[n],ans[n];
char s[n];
vector
g[n];
struct quesa[n];
bool cmp(ques a,ques b)e[n];
void add(int u,int v)
struct bit
}tree;
struct ac_dfa}}
void getfail()
for(int i=1;i<=tot;i++) g[fail[i]].push_back(i);
}void dfs(int x)
}else
if(s[i]=='b') tree.updata(in[x],-1),x=fa[x];
else x=c[x][idx],tree.updata(in[x],1);}}
}ac;
void work()
void init()
int main()
BZOJ2434 NOI2011 阿狸的打字機
發現一種新的思路,以前從來沒有見過的,即ac自動機的fail樹。這一題我們先考慮暴力,從root往y的最後乙個點走,如果走到了x的末點,ans 如果通過fail指標走到了x的末點,ans 反過來考慮,從x的末點開始,如果當前點在y串或者通過反向的fail到了y串,ans 又發把fail反向之後得到的...
bzoj2434 Noi2011 阿狸的打字機
傳送門 description 阿狸喜歡收藏各種稀奇古怪的東西,最近他淘到一台老式的打字機。打字機上只有28個按鍵,分別印有26個小寫英文本母和 b p 兩個字母。經阿狸研究發現,這個打字機是這樣工作的 l 輸入小寫字母,打字機的乙個凹槽中會加入這個字母 這個字母加在凹槽的最後 l 按一下印有 b ...
bzoj 2434 Noi2011 阿狸的打字機
time limit 10 sec memory limit 256 mb submit 3139 solved 1731 submit status discuss 阿狸喜歡收藏各種稀奇古怪的東西,最近他淘到一台老式的打字機。打字機上只有28個按鍵,分別印有26個小寫英文本母和 b p 兩個字母。...