zoukankan      html  css  js  c++  java
  • BZOJ2434: [Noi2011]阿狸的打字机(fail树+dfs序)

    Description

     阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机。打字机上只有28个按键,分别印有26个小写英文字母和'B'、'P'两个字母。

    经阿狸研究发现,这个打字机是这样工作的:

    l 输入小写字母,打字机的一个凹槽中会加入这个字母(这个字母加在凹槽的最后)。

    l 按一下印有'B'的按键,打字机凹槽中最后一个字母会消失。

    l 按一下印有'P'的按键,打字机会在纸上打印出凹槽中现有的所有字母并换行,但凹槽中的字母不会消失。

    例如,阿狸输入aPaPBbP,纸上被打印的字符如下:

    a

    aa

    ab

    我们把纸上打印出来的字符串从1开始顺序编号,一直到n。打字机有一个非常有趣的功能,在打字机中暗藏一个带数字的小键盘,在小键盘上输入两个数(x,y)(其中1≤x,y≤n),打字机会显示第x个打印的字符串在第y个打印的字符串中出现了多少次。

    阿狸发现了这个功能以后很兴奋,他想写个程序完成同样的功能,你能帮助他么?

    Input

     输入的第一行包含一个字符串,按阿狸的输入顺序给出所有阿狸输入的字符。

    第二行包含一个整数m,表示询问个数。

    接下来m行描述所有由小键盘输入的询问。其中第i行包含两个整数x, y,表示第i个询问为(x, y)。

    Output

     输出m行,其中第i行包含一个整数,表示第i个询问的答案。

    Sample Input

    aPaPBbP
    3
    1 2
    1 3
    2 3

    Sample Output

    2
    1
    0

    解题思路:

    长得像不像可持久化数据结构,这道题是可持久化Trie树

    然而并没有强制在线a

    曾经有个dalao说过:长得像可持久化+不强制在线=离线。

    假如说没有问你a串在b串中出现多少次,BZOJ3172fail树裸上。

    fail树中子节点个数为出现次数。

    先按照打字顺序将trie树、trie图、fail树建好。

    trie树要支持回溯(记录父节点)

    将询问排序,按y串位置。

    我们可以这样认为:

    在询问版本中存在的点点权为1,不存在为0

    这样统计子树大小时无需重构,更新点权即可。

    再遍历原串。

    遇到P

    更新答案。

    遇到其他:

    改变一个点的点权。

    当然不能暴力更新了。

    询问子树权值和和更改单点点值当然要用dfs序了

    代码:

      1 #include<queue>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<algorithm>
      5 const int N=1000000;
      6 struct trnt{
      7     int ch[26];
      8     int fl;
      9     int ind;
     10     int oud;
     11     int hd;
     12     int fa;
     13 }tr[N];
     14 struct ent{
     15     int twd;
     16     int lst;
     17 }e[N];
     18 struct qus{
     19     int asp;
     20     int plc;
     21     int no;
     22     int ans;
     23 }q[N];
     24 int lne[N];
     25 char ch[N];
     26 int fin[N];
     27 int len;
     28 int pct;
     29 int siz;
     30 int cnt;
     31 int n,m,dfn;
     32 std::queue<int>Q;
     33 void ade(int f,int t)
     34 {
     35     cnt++;
     36     e[cnt].twd=t;
     37     e[cnt].lst=tr[f].hd;
     38     tr[f].hd=cnt;
     39 }
     40 bool cmp(qus x,qus y)
     41 {
     42     return x.plc<y.plc;
     43 }
     44 bool cmq(qus x,qus y)
     45 {
     46     return x.no<y.no;
     47 }
     48 int lowbit(int x)
     49 {
     50     return x&(-x);
     51 }
     52 void add(int p,int v)
     53 {
     54     while(p<=len&&p)
     55     {
     56         lne[p]+=v;
     57         p+=lowbit(p);
     58     }
     59     return ;
     60 }
     61 int Val(int p)
     62 {
     63     int ans=0;
     64     while(p)
     65     {
     66         ans+=lne[p];
     67         p-=lowbit(p);
     68     }
     69     return ans;
     70 }
     71 void dfs(int x)
     72 {
     73     tr[x].ind=++dfn;
     74     for(int i=tr[x].hd;i;i=e[i].lst)
     75     {
     76         int to=e[i].twd;
     77         dfs(to);
     78     }
     79     tr[x].oud=dfn;
     80     return ;
     81 }
     82 void Build()
     83 {
     84     int root=0;
     85     len=strlen(ch+1);
     86     for(int i=1;i<=len;i++)
     87     {
     88         if(ch[i]=='P')
     89         {
     90             fin[++pct]=root;
     91         }else if(ch[i]=='B')
     92         {
     93             root=tr[root].fa;
     94         }else{
     95             int tmp=root;
     96             int c=ch[i]-'a';
     97             if(!tr[root].ch[c])
     98                 tr[root].ch[c]=++siz;
     99             root=tr[root].ch[c];
    100             tr[root].fa=tmp;
    101         }
    102     }
    103     root=0;
    104     for(int i=0;i<26;i++)
    105         if(tr[root].ch[i])
    106             Q.push(tr[root].ch[i]);
    107     while(!Q.empty())
    108     {
    109         root=Q.front();
    110         Q.pop();
    111         for(int i=0;i<26;i++)
    112         {
    113             if(tr[root].ch[i])
    114             {
    115                 tr[tr[root].ch[i]].fl=tr[tr[root].fl].ch[i];
    116                 Q.push(tr[root].ch[i]);
    117             }else
    118                 tr[root].ch[i]=tr[tr[root].fl].ch[i];
    119         }
    120     }
    121     for(int i=1;i<=siz;i++)
    122         ade(tr[i].fl,i);
    123     dfs(0);
    124     return ;
    125 }
    126 void Get_ans()
    127 {
    128     std::sort(q+1,q+m+1,cmp);
    129     int i=1;
    130     int root=0;
    131     int num=0;
    132     for(int k=1;k<=len;k++)
    133     {
    134         if(ch[k]=='P')
    135         {
    136             num++;
    137             while(q[i].plc<num&&i<=m)
    138                 i++;
    139             while(q[i].plc==num&&i<=m)
    140             {
    141                 int j=fin[q[i].asp];
    142                 int h=Val(tr[j].oud);
    143                 int o=Val(tr[j].ind-1);
    144                 q[i].ans=h-o;
    145                 i++;
    146             }
    147         }else if(ch[k]=='B')
    148         {
    149             add(tr[root].ind,-1);
    150             root=tr[root].fa;
    151         }else{
    152             root=tr[root].ch[ch[k]-'a'];
    153             add(tr[root].ind,1);
    154         }
    155     }
    156     std::sort(q+1,q+m+1,cmq);
    157     return ;
    158 }
    159 int main()
    160 {
    161     scanf("%s",ch+1);
    162     scanf("%d",&m);
    163     for(int i=1;i<=m;i++)
    164     {
    165         scanf("%d%d",&q[i].asp,&q[i].plc);
    166         q[i].no=i;
    167     }
    168     Build();
    169     Get_ans();
    170     for(int i=1;i<=m;i++)
    171         printf("%d
    ",q[i].ans);
    172     return 0;
    173 }
  • 相关阅读:
    CDialogConfigStringRecord+CDialogConfigManage 如何保存listbox中未显示的信息
    vs2010 打开 vs2005 工程报错
    优秀程序员的两大要素:懒 + 笨
    架构设计中的方法学(四)
    程序员应该具备的素质汇总(逐步总结)(转)
    架构设计中的方法学(三)
    成都中青旅欢迎你
    游洪崖洞有感
    架构设计中的方法学(七)
    架构设计中的方法学(二)
  • 原文地址:https://www.cnblogs.com/blog-Dr-J/p/9674307.html
Copyright © 2011-2022 走看看