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 }

 

posted @ 2019-01-04 19:28  menhera  阅读(146)  评论(0编辑  收藏  举报