首页 > 代码库 > bzoj 2434 阿狸的打字机 fail树的性质

bzoj 2434 阿狸的打字机 fail树的性质

      如果a串是另b串的后缀,那么在trie图上沿着b的fail指针走一定可以走到a串。

      而a串在b串里出现多少次就是它是多少个前缀的后缀。

      所以把fail边反向建树维护个dfs序就行了。

      并不是很难。。。但没想出来TAT

     

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<algorithm>
  4 #include<cstring>
  5 #define N 200005
  6 #define inf 0x3f3f3f3f
  7 using namespace std;
  8 int n;
  9 int ch[N][2], fa[N];
 10 int a[N];
 11 int mn[N],zhi[N],size[N];
 12 void push_up(int x)
 13 {
 14     size[x] = size[ch[x][0]] + size[ch[x][1]] + 1;
 15     mn[x] = min(zhi[x], min(mn[ch[x][0]], mn[ch[x][1]])); return;
 16 }
 17 int rev[N];
 18 void push_down(int x)
 19 {
 20     if (rev[x])
 21     {
 22         rev[x] ^= 1; rev[ch[x][1]] ^= 1; rev[ch[x][0]] ^= 1;
 23         swap(ch[x][0], ch[x][1]);
 24     }
 25     return;
 26 }
 27 void rotate(int p)
 28 {
 29     int q = fa[p], y = fa[q], x = (ch[q][1] == p);
 30     ch[q][x] = ch[p][x ^ 1]; fa[ch[q][x]] = q;
 31     ch[p][x ^ 1] = q; fa[q] = p;
 32     fa[p] = y;
 33     if (y)
 34     {
 35         if (ch[y][1] == q)ch[y][1] = p;
 36         else ch[y][0] = p;
 37     }
 38     push_up(q); return;
 39 }
 40 int root;
 41 void splay(int x,int yy)
 42 {
 43     for (int y; y = fa[x]; rotate(x))
 44     {
 45         if (y == yy)break;
 46         if (fa[y] != yy)
 47         {
 48             if ((ch[fa[y]][0] == y) ^ (ch[y][0] == x))rotate(x);
 49             else rotate(y);
 50         }
 51     }
 52     push_up(x);
 53     if (!yy)root = x;
 54 }
 55 int cnt;
 56 int find(int k, int x)
 57 {
 58     push_down(k);
 59     if (mn[ch[k][0]] == x)
 60     {
 61         return find(ch[k][0], x);
 62     }
 63     if (zhi[k] == x)return size[ch[k][0]] + 1;
 64     return find(ch[k][1], x) + size[ch[k][0]] + 1;
 65 }
 66 int fd(int k, int x)
 67 {
 68     push_down(k);
 69     if (size[ch[k][0]] + 1 == x)return k;
 70     if (size[ch[k][0]] + 1 >= x)return fd(ch[k][0],x);
 71     return fd(ch[k][1], x - size[ch[k][0]] - 1);
 72 }
 73 struct node
 74 {
 75     int yuan,z;
 76     friend bool operator < (node aa,node bb)
 77     {
 78         if(aa.z!=bb.z)return aa.z<bb.z;
 79         return aa.yuan<bb.yuan;
 80     }
 81 }s[N];
 82 int yin[N];
 83 int main()
 84 {
 85     scanf("%d", &n); mn[0] = inf;
 86     for (int i = 1; i <= n; i++)
 87     {
 88         s[i].yuan=i;scanf("%d",&s[i].z);
 89     }
 90     sort(s+1,s+n+1);
 91     for(int i=1;i<=n;i++)
 92     {
 93         a[s[i].yuan]=i;
 94     }
 95     root = 1; a[n + 1] = inf; 
 96     ch[1][1] = 2; zhi[1] = a[1]; size[1] = n + 1;
 97     for (int i = 2; i <= n + 1; i++)
 98     {
 99         size[i] = n - i + 2;
100         zhi[i] = a[i]; fa[i] = i - 1; ch[i - 1][1] = i;
101     }
102     for (int i = n + 1; i >= 1; i--)push_up(i);
103     splay(n, 0);
104     for (int i = 1; i <= n; i++)
105     {
106         int y = find(root, mn[root]);
107         if(i!=n)printf("%d ",y+(i-1));
108         else printf("%d",y+(i-1));
109         int t = fd(root, y+1);
110         splay(t, 0);
111         rev[ch[t][0]] ^= 1;
112         t = fd(root, 2);
113         splay(t, 0);
114         ch[t][0] = 0;
115         push_up(t);
116     }
117     puts("");
118     return 0;
119 }

 

bzoj 2434 阿狸的打字机 fail树的性质