zoukankan      html  css  js  c++  java
  • BZOJ2434: [Noi2011]阿狸的打字机

    2434: [Noi2011]阿狸的打字机

    Time Limit: 10 Sec  Memory Limit: 256 MB
    Submit: 1166  Solved: 656
    [Submit][Status]

    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

    HINT

     1<=N<=10^5


    1<=M<=10^5

    输入总长<=10^5

    Source

    Trie

    题解:
    终于填上了一个大坑。。。
    首先我们建出AC自动机,然后以fail[i]作为i的父亲构建fail树,那么如果要查询s[x]在s[y]中出现了多少次,实际上就是询问
    s[x]的结尾节点的子树中有多少是s[y]的节点。
    考虑离线的做法,我们对每一个结尾节点保存一个链表表示要查询哪个串在该串中出现的次数。
    我们发现有子树查询,然后按fail树进行dfs序,标记l[x],r[x]分别为左端点和右端点。
    然后继续,我们在trie上dfs
    inline void dfs2(int x)
    {
        add(l[x],1);
        for(int i=head[1][a[x]];i;i=e[1][i].next)ans[i]=sum(r[b[e[1][i].go]])-sum(l[b[e[1][i].go]]-1);
        for0(i,25)if(t[x][i]>x)dfs2(t[x][i]);
        add(r[x],-1);
    }

    可以看出,当我们到达x节点时,只有根到x的节点的括号序列是没有闭合的,呈现(,而已经访问结束的或者未访问的呈现()或 空,这样它们对答案的贡献都是0

    所以我们执行直接求和sum(l[x]-r[x])就可以求出s[y]的节点中有多少个是s[x]的子树。

    代码:

      1 #include<cstdio>
      2 
      3 #include<cstdlib>
      4 
      5 #include<cmath>
      6 
      7 #include<cstring>
      8 
      9 #include<algorithm>
     10 
     11 #include<iostream>
     12 
     13 #include<vector>
     14 
     15 #include<map>
     16 
     17 #include<set>
     18 
     19 #include<queue>
     20 
     21 #include<string>
     22 
     23 #define inf 1000000000
     24 
     25 #define maxn 250000+5
     26 
     27 #define maxm 20000000+5
     28 
     29 #define eps 1e-10
     30 
     31 #define ll long long
     32 
     33 #define pa pair<int,int>
     34 
     35 #define for0(i,n) for(int i=0;i<=(n);i++)
     36 
     37 #define for1(i,n) for(int i=1;i<=(n);i++)
     38 
     39 #define for2(i,x,y) for(int i=(x);i<=(y);i++)
     40 
     41 #define for3(i,x,y) for(int i=(x);i>=(y);i--)
     42 
     43 #define mod 1000000007
     44 
     45 using namespace std;
     46 
     47 inline int read()
     48 
     49 {
     50 
     51     int x=0,f=1;char ch=getchar();
     52 
     53     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
     54 
     55     while(ch>='0'&&ch<='9'){x=10*x+ch-'0';ch=getchar();}
     56 
     57     return x*f;
     58 
     59 }
     60 int n,m,mm,cnt,tot[2],head[2][maxn],t[maxn][26],go[maxn],l[maxn],r[maxn];
     61 int ans[maxn],a[maxn],b[maxn],p[maxn],pre[maxn],s[maxn];
     62 struct edge{int go,next;}e[2][maxn];
     63 queue<int>q;
     64 char st[maxn];
     65 inline void insert(int k,int x,int y)
     66 {
     67     e[k][++tot[k]]=(edge){y,head[k][x]};head[k][x]=tot[k];
     68 }
     69 void bfs()
     70 {
     71     q.push(1);
     72     while(!q.empty())
     73     {
     74         int x=q.front(),y,j;q.pop();
     75         for0(i,25)if(t[x][i])
     76         {
     77             j=go[x];
     78             while(j&&!t[j][i])j=go[j];
     79             go[y=t[x][i]]=j?t[j][i]:1;
     80             insert(0,go[y],y);
     81             q.push(y);
     82         }
     83     }
     84 }
     85 inline void add(int x,int y){for(;x<=2*n;x+=x&(-x))s[x]+=y;}
     86 inline int sum(int x){int t=0;for(;x;x-=x&(-x))t+=s[x];return t;}
     87 inline void dfs(int x)
     88 {
     89     l[x]=++mm;
     90     for(int i=head[0][x];i;i=e[0][i].next)dfs(e[0][i].go);
     91     r[x]=++mm;
     92 }
     93 inline void dfs2(int x)
     94 {
     95     add(l[x],1);
     96     for(int i=head[1][a[x]];i;i=e[1][i].next)ans[i]=sum(r[b[e[1][i].go]])-sum(l[b[e[1][i].go]]-1);
     97     for0(i,25)if(t[x][i]>x)dfs2(t[x][i]);
     98     add(r[x],-1);
     99 }
    100 void putint(int t ){
    101     if(! t )putchar('0')
    102     ;else{
    103         int a[20];
    104         a[0]=0;
    105         for(;t;t/=10)a[++a[0]]=t%10;
    106         for3(i,a[0],1)putchar('0'+a[i]);
    107     }
    108     putchar('
    ');
    109 }
    110 
    111 int main()
    112 
    113 {
    114 
    115     freopen("input.txt","r",stdin);
    116 
    117     freopen("output.txt","w",stdout);
    118 
    119     n=0;
    120     while(1)
    121     {
    122         char ch=getchar();
    123         if(ch=='B'||ch=='P'||(ch<='z'&&ch>='a'))st[++n]=ch;
    124         if(ch=='
    '||ch=='
    ')break;
    125     }
    126     m=read();
    127     for1(i,m)
    128     {
    129         int x=read(),y=read();
    130         insert(1,y,x);
    131     }
    132     int now=cnt=1,id=0;
    133     for1(i,n)
    134     if(st[i]=='P')a[now]=++id,b[id]=now;
    135     else if(st[i]=='B'){p[i]=now;now=pre[now];}
    136     else 
    137         {
    138             int x=st[i]-'a';
    139             if(!t[now][x])t[now][x]=++cnt,pre[cnt]=now;
    140             now=t[now][x];p[i]=now;
    141         }
    142     bfs();
    143     dfs(1);
    144     dfs2(1);
    145     for1(i,m)putint(ans[i]);
    146 
    147     return 0;
    148 
    149 }  
    View Code

    还有一种查询方法如下,蒟蒻表示理解不能。。。

    代码:

      1 #include<cstdio>
      2 
      3 #include<cstdlib>
      4 
      5 #include<cmath>
      6 
      7 #include<cstring>
      8 
      9 #include<algorithm>
     10 
     11 #include<iostream>
     12 
     13 #include<vector>
     14 
     15 #include<map>
     16 
     17 #include<set>
     18 
     19 #include<queue>
     20 
     21 #include<string>
     22 
     23 #define inf 1000000000
     24 
     25 #define maxn 250000+5
     26 
     27 #define maxm 20000000+5
     28 
     29 #define eps 1e-10
     30 
     31 #define ll long long
     32 
     33 #define pa pair<int,int>
     34 
     35 #define for0(i,n) for(int i=0;i<=(n);i++)
     36 
     37 #define for1(i,n) for(int i=1;i<=(n);i++)
     38 
     39 #define for2(i,x,y) for(int i=(x);i<=(y);i++)
     40 
     41 #define for3(i,x,y) for(int i=(x);i>=(y);i--)
     42 
     43 #define mod 1000000007
     44 
     45 using namespace std;
     46 
     47 inline int read()
     48 
     49 {
     50 
     51     int x=0,f=1;char ch=getchar();
     52 
     53     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
     54 
     55     while(ch>='0'&&ch<='9'){x=10*x+ch-'0';ch=getchar();}
     56 
     57     return x*f;
     58 
     59 }
     60 int n,m,mm,cnt,tot[2],head[2][maxn],t[maxn][26],go[maxn],l[maxn],r[maxn];
     61 int ans[maxn],pos[maxn],p[maxn],pre[maxn],s[maxn];
     62 struct edge{int go,next;}e[2][maxn];
     63 queue<int>q;
     64 char st[maxn];
     65 inline void insert(int k,int x,int y)
     66 {
     67     e[k][++tot[k]]=(edge){y,head[k][x]};head[k][x]=tot[k];
     68 }
     69 void bfs()
     70 {
     71     q.push(1);
     72     while(!q.empty())
     73     {
     74         int x=q.front(),y,j;q.pop();
     75         for0(i,25)
     76         {
     77             j=go[x];
     78             while(j&&!t[j][i])j=go[j];
     79             if(t[x][i])
     80             {
     81                 go[y=t[x][i]]=j?t[j][i]:1;
     82                 insert(0,go[y],y);
     83                 q.push(y);
     84             }else t[x][i]=j?t[j][i]:1;
     85         }
     86     }
     87 }
     88 inline void add(int x,int y){for(;x<=2*n;x+=x&(-x))s[x]+=y;}
     89 inline int sum(int x){int t=0;for(;x;x-=x&(-x))t+=s[x];return t;}
     90 inline void dfs(int x)
     91 {
     92     l[x]=++mm;
     93     for(int i=head[0][x];i;i=e[0][i].next)dfs(e[0][i].go);
     94     r[x]=++mm;
     95 }
     96 void putint(int t ){
     97     if(! t )putchar('0')
     98     ;else{
     99         int a[20];
    100         a[0]=0;
    101         for(;t;t/=10)a[++a[0]]=t%10;
    102         for3(i,a[0],1)putchar('0'+a[i]);
    103     }
    104     putchar('
    ');
    105 }
    106 
    107 int main()
    108 
    109 {
    110 
    111     freopen("input.txt","r",stdin);
    112 
    113     freopen("output.txt","w",stdout);
    114 
    115     n=0;
    116     while(1)
    117     {
    118         char ch=getchar();
    119         if(ch=='B'||ch=='P'||(ch<='z'&&ch>='a'))st[++n]=ch;
    120         if(ch=='
    '||ch=='
    ')break;
    121     }
    122     m=read();
    123     for1(i,m)
    124     {
    125         int x=read(),y=read();
    126         insert(1,y,x);
    127     }
    128     int now=cnt=1,id=0;
    129     for1(i,n)
    130     if(st[i]=='P')pos[++id]=now;
    131     else if(st[i]=='B'){p[i]=now;now=pre[now];}
    132     else 
    133         {
    134             int x=st[i]-'a';
    135             if(!t[now][x])t[now][x]=++cnt,pre[cnt]=now;
    136             now=t[now][x];p[i]=now;
    137         }
    138     bfs();
    139     dfs(1);
    140     id=0;
    141     for1(i,n)
    142     if(st[i]=='P'){for(int j=head[1][++id];j;j=e[1][j].next)ans[j]=sum(r[pos[e[1][j].go]])-sum(l[pos[e[1][j].go]]-1);}
    143     else if(st[i]=='B')add(r[p[i]],-1);else add(l[p[i]],1);
    144     for1(i,m)putint(ans[i]);
    145     return 0;
    146 
    147 }  
    View Code
  • 相关阅读:
    SpringBoot发送邮箱验证码
    判断一个数是否为2的整数次幂
    [模板] 虚树 && bzoj2286-[Sdoi2011]消耗战
    [模板] K-D Tree
    [模板] 平衡树: Splay, 非旋Treap, 替罪羊树
    对于约数个数上界的估计
    luogu3702-[SDOI2017]序列计数
    [模板] 线性基
    [模板] 区间mex && 区间元素种数
    bzoj4367-[IOI2014]holiday假期
  • 原文地址:https://www.cnblogs.com/zyfzyf/p/4155192.html
Copyright © 2011-2022 走看看