BZOJ2434 [NOI2011] 阿狸的打字机 【树链剖分】【线段树】【fail树】【AC自动机】
题目分析:
画一下fail树,就会发现就是x的子树中属于y路径的,把y剖分一下,用线段树处理
$O(n*log^2 n)$。
代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 const int maxn = 102000; 5 6 string str; 7 struct node{int ch[26],fail,fa;}T[maxn]; 8 int star[maxn],ans[maxn],num = 1,snum,m; 9 int dfsin[maxn],dfsout[maxn],poss[maxn]; // failtree 10 int Tnb[maxn],top[maxn],sz[maxn]; 11 vector <int> g[maxn]; 12 vector<pair<int,int> > Qy[maxn]; 13 14 void read(){ 15 ios::sync_with_stdio(false); 16 cin.tie(0); 17 cin >> str; 18 int now = 1; 19 for(int i=0;i<str.length();i++){ 20 if(str[i] == 'B') now = T[now].fa; 21 else if(str[i] == 'P') star[++snum] = now; 22 else{ 23 if(T[now].ch[str[i]-'a']) now = T[now].ch[str[i]-'a']; 24 else{ 25 T[now].ch[str[i]-'a'] = ++num; 26 T[num].fa = now; 27 now = num; 28 } 29 } 30 } 31 snum = 0; 32 } 33 34 void dfs(int now){ 35 dfsin[now] = dfsout[now] = ++snum; 36 poss[snum] = now; 37 for(int i=0;i<g[now].size();i++){ 38 dfs(g[now][i]); 39 dfsout[now] = dfsout[g[now][i]]; 40 } 41 } 42 43 queue<int> q; 44 void BuildACAutomaton(){ 45 q.push(1);T[1].fail = 1; 46 while(!q.empty()){ 47 int k = q.front();q.pop(); 48 for(int i=0;i<26;i++){ 49 if(T[k].ch[i] == 0) continue; 50 int ff = T[k].fail; 51 while(ff != 1 && T[ff].ch[i] == 0) ff = T[ff].fail; 52 if(T[ff].ch[i]==T[k].ch[i]||T[ff].ch[i]==0)T[T[k].ch[i]].fail=1; 53 else T[T[k].ch[i]].fail = T[ff].ch[i]; 54 q.push(T[k].ch[i]); 55 g[T[T[k].ch[i]].fail].push_back(T[k].ch[i]); 56 } 57 } 58 snum = 0; dfs(1); snum = 0; 59 } 60 61 int QT[maxn*4]; 62 63 void Add(int now,int tl,int tr,int pos){ 64 if(tl == tr){QT[now]++;return;} 65 int mid = (tl+tr)/2;QT[now]++; 66 if(mid >= pos) Add(now<<1,tl,mid,pos); 67 else Add(now<<1|1,mid+1,tr,pos); 68 } 69 int Query(int now,int tl,int tr,int l,int r){ 70 if(tl >= l && tr <= r) return QT[now]; 71 if(tl > r || tr < l) return 0; 72 int mid = (tl+tr)/2; 73 return Query(now<<1,tl,mid,l,r)+Query(now<<1|1,mid+1,tr,l,r); 74 } 75 76 void dfsmiao(int now){ 77 for(int i=0;i<26;i++){ 78 if(T[now].ch[i]==0)continue; 79 dfsmiao(T[now].ch[i]); 80 sz[now] += sz[T[now].ch[i]]; 81 } 82 sz[now]++; 83 } 84 85 void dfsyeah(int now,int tp){ 86 int son = 0;top[now] = tp;Tnb[now] = ++snum; 87 for(int i=0;i<26;i++){ 88 if(sz[T[now].ch[i]] > sz[son]) son = T[now].ch[i]; 89 } 90 if(son) dfsyeah(son,tp); 91 for(int i=0;i<26;i++){ 92 if(T[now].ch[i] == 0 || T[now].ch[i] == son) continue; 93 dfsyeah(T[now].ch[i],T[now].ch[i]); 94 } 95 } 96 97 void treechain(){ 98 dfsmiao(1); 99 dfsyeah(1,1); 100 } 101 102 void readquery(){ 103 cin >> m; 104 for(int i=1;i<=m;i++){ 105 int x,y; cin >> x >> y; 106 x = star[x];y = star[y]; 107 Qy[poss[dfsin[x]-1]].push_back(make_pair(y,i)); 108 Qy[poss[dfsout[x]]].push_back(make_pair(y,i)); 109 } 110 } 111 112 void solve(int endpos,int now){ 113 if(ans[now]) ans[now] = -ans[now]; 114 while(endpos){ 115 ans[now] += Query(1,1,num,Tnb[top[endpos]],Tnb[endpos]); 116 endpos = T[top[endpos]].fa; 117 } 118 } 119 120 void work(){ 121 for(int i=1;i<=num;i++){ 122 int now = poss[i]; 123 Add(1,1,num,Tnb[now]); 124 for(int j=0;j<Qy[now].size();j++){ 125 solve(Qy[now][j].first,Qy[now][j].second); 126 } 127 } 128 for(int i=1;i<=m;i++) cout<<ans[i]<<endl; 129 } 130 131 int main(){ 132 //freopen("7.in","r",stdin); 133 read(); 134 treechain(); 135 BuildACAutomaton(); 136 readquery(); 137 work(); 138 return 0; 139 }