NOI 2011 阿狸的打字机

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=2434
思路:AC自动机,离线处理,主要利用fail树的性质,然而我犯傻了,dfs序总是犯晕,wa好多次,应该引起重视,再总结一下dfs序
代码:

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<cmath> 
#define N 100000
using namespace std;
struct edge{int nxt,point,v;}; 
struct node { int x,y,ans,id;};
struct trie{ int judge,fa,a[26],fail; }; 
node ask[N + 5]; 
trie T[N + 5];
edge e[(N << 2) + 5]; 
char s[N + 5];
int m,num,cnt,s0[N + 5],id1[N + 5],st[N + 5],tt[N + 5],que[N + 5],l[N + 5],r[N + 5],top,c[N + 5]; 
inline bool cmp(node a,node b){ return (a.y < b.y); } 
inline bool cmp1(node a,node b){ return (a.id < b.id); } 
inline void addedge(int u1,int v1){  e[++cnt].nxt = e[u1].point; e[u1].point = cnt; e[cnt].v = v1;} 
inline void insert(int u1,int v1){ addedge(u1,v1); addedge(v1,u1);} 
inline int lowbit(int x) { return (x&(-x));}
inline void add(int posi,int x){ for (int i = posi;i <= top; i += lowbit(i)) c[i] += x;} 
inline int query(int posi) {
   int sum = 0;
   for (int i = posi;i;i -= lowbit(i)) sum += c[i];
   return sum;
}
inline int getnum(){
    char c; int num;
    while (!isdigit(c = getchar()));
    num = c - '0';
    while (isdigit(c = getchar())) num = 10 * num + c - '0';
    return num;
}

void make_trie(){
   int l = strlen(s + 1),q = 0;
   num = 0; cnt = 0;
   for (int i = 1;i <= l; ++i)
       if (s[i] == 'P') s0[++num] = q,id1[q] = num,T[q].judge++;
       else if (s[i] == 'B') q = T[q].fa;
       else {  int k = s[i] - 'a';
               if (!T[q].a[k]) T[q].a[k] = ++cnt;
               T[T[q].a[k]].fa = q; 
               q = T[q].a[k]; } 
    //cout<<cnt<<endl;
}

void init(){
   scanf("%s",s + 1);
   m = getnum(); 
   make_trie();
   for (int i = 1;i <= m; ++i) ask[i].x = getnum(),ask[i].y = getnum(),ask[i].id = i;
   for (int i = 1;i <= m; ++i) ask[i].x = s0[ask[i].x],ask[i].y = s0[ask[i].y]; 
   sort(ask + 1,ask + m + 1,cmp); 
   for (int i = 1;i <= m; ++i){ 
     if (ask[i].y !=  ask[i - 1].y) st[ask[i].y] = i;
     if (ask[i].y != ask[i + 1].y) tt[ask[i].y] = i; }
    //for (int i = 1;i <= m; ++i) cout<<ask[i].x<<" "<<ask[i].y<<endl; 
   //for (int i = 1;i <= cnt; ++i) cout<<id1[i]<<endl; 
   //for (int i = 1;i <= num; ++i) cout<<s0[i]<<endl; 
   top = 0;
}

void make_ac(){
   int head = 0,tail = 1; cnt = 0;
   que[1] = 0;
   while (head < tail){
      int x = que[++head];
      for (int i = 0;i < 26; ++i)
        if (T[x].a[i]) 
      {
         que[++tail] = T[x].a[i]; 
         if (x){ 
         int q = T[x].fail;
         while (q&&!T[q].a[i]) q = T[q].fail; 
         T[T[x].a[i]].fail = T[q].a[i];}
         insert(T[x].a[i],T[T[x].a[i]].fail); 
      }
   }
}

inline void dfs(int x){
   l[x] = ++top;
   for (int p = e[x].point;p;p = e[p].nxt)
     if (!l[e[p].v]) dfs(e[p].v);
   r[x] = top;
}

inline void dfs1(int x){
    add(l[x],1); 
    if (T[x].judge) 
      for (int i = st[x];i <= tt[x]; ++i) ask[i].ans = query(r[ask[i].x]) - query(l[ask[i].x] - 1); 
    for (int i = 0;i < 26; ++i)
      if (T[x].a[i]) dfs1(T[x].a[i]); 
    add(l[x],-1);
}

void DO_IT(){
    make_ac();
    //for (int i = 1;i <= 8; ++i) cout<<T[i].fail<<endl; 
    dfs(0); 
    dfs1(0); 
}

void print(){
   sort(ask + 1,ask + m + 1,cmp1);
   for (int i = 1;i <= m; ++i) printf("%d\n",ask[i].ans);
}

int main(){
   init();
   DO_IT();
   print();
   return 0;
}

你可能感兴趣的:(NOI 2011 阿狸的打字机)