zoukankan      html  css  js  c++  java
  • [BZOJ2434][Noi2011]阿狸的打字机 AC自动机+树状数组+离线

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2434

    题目中这种多个串匹配的问题,一下子就想到了AC自动机。然后发现如果要建立AC自动机,跟着题目中的方式,不用把每个串提出来。如果是一个普通字符就直接加进去,如果是P就把当前节点记录下来,代表一个串,如果是B就相当于退回到trie树中的父亲节点。

    建好AC自动机后来观察一下题目中的问题。这个询问相当于统计从根节点到代表y串的那个节点上的路径上,有多少个节点可以通过跳fail指针的方式到达x串的节点。

    暴力统计显然是不行的,观察到fail路径上的每一个点的出度都为1,那么将fail全部反过来就是一棵树。问题就变成了在x的子树中,有多少个从根节点到y串的节点的路径上的节点。把fail树的dfs序求出来,我们可以用树状数组求子树和。

    考虑离线。那么重新模拟题目中打字的过程,如果加入了一个字符,对应树状数组中此节点dfs序的位置+1,如果被删除了,则-1。这样就能实时维护树状数组中的点全部是y串中的点,于是提前处理一下,如果有关于y串的询问,答案就是x串的子树和,也就是dfs序对应的区间和。

      1 #include<cstdio>
      2 #include<cstring>
      3 #include<algorithm>
      4 using namespace std;
      5 int inline readint(){
      6     int Num;char ch;
      7     while((ch=getchar())<'0'||ch>'9');Num=ch-'0';
      8     while((ch=getchar())>='0'&&ch<='9') Num=Num*10+ch-'0';
      9     return Num;
     10 }
     11 void outint(int x){
     12     if(x>=10) outint(x/10);
     13     putchar(x%10+'0');
     14 }
     15 char s[100010];
     16 int Len,M;
     17 int ch[100010][26],fa[100010],sz=0;
     18 int pos[100010],tot=0;
     19 void Build_trie(){
     20     int now=0;
     21     for(int i=1;i<=Len;i++){
     22         if(s[i]>='a'&&s[i]<='z'){
     23             int idx=s[i]-'a';
     24             if(!ch[now][idx]) ch[now][idx]=++sz;
     25             fa[ch[now][idx]]=now;
     26             now=ch[now][idx];
     27         }
     28         else if(s[i]=='B') now=fa[now];
     29         else pos[++tot]=now;
     30     }
     31 }
     32 int to[100010],ne[100010],fir[100010],cnt=0;
     33 void Addedge(int a,int b){
     34     to[++cnt]=b;
     35     ne[cnt]=fir[a];
     36     fir[a]=cnt;
     37 }
     38 int fail[100010],q[100010];
     39 void Set_fail(){
     40     memset(fir,-1,sizeof(fir));
     41     int head=1,tail=1;
     42     q[1]=0;
     43     while(head<=tail){
     44         int now=q[head];
     45         for(int i=0;i<26;i++){
     46             if(ch[now][i]){
     47                 q[++tail]=ch[now][i];
     48                 int tmp=now?ch[fail[now]][i]:0;
     49                 fail[ch[now][i]]=tmp;
     50                 Addedge(tmp,ch[now][i]);
     51             }
     52             else ch[now][i]=ch[fail[now]][i];
     53         }
     54         head++;
     55     }
     56 }
     57 int dfn=0,in[100010],out[100010];
     58 void Dfs(int x){
     59     in[x]=++dfn;
     60     for(int i=fir[x];i!=-1;i=ne[i]) Dfs(to[i]);
     61     out[x]=dfn;
     62 }
     63 struct Query{
     64     int x,y,idx;
     65     bool operator < (const Query &_)const{
     66         return y<_.y;
     67     }
     68 }qry[100010];
     69 int tree[100010];
     70 int inline lowbit(int &x){
     71     return x&-x;
     72 }
     73 void Add(int x,int d){
     74     while(x<=dfn){
     75         tree[x]+=d;
     76         x+=lowbit(x);
     77     }
     78 }
     79 int Sum(int x){
     80     int sum=0;
     81     while(x){
     82         sum+=tree[x];
     83         x-=lowbit(x);
     84     }
     85     return sum;
     86 }
     87 int Ans[100010];
     88 int main(){
     89     scanf("%s",s+1);
     90     Len=strlen(s+1);
     91     Build_trie();
     92     Set_fail();
     93     Dfs(0);
     94     M=readint();
     95     for(int i=1;i<=M;i++){
     96         qry[i].x=readint();
     97         qry[i].y=readint();
     98         qry[i].idx=i;
     99     }
    100     sort(qry+1,qry+1+M);
    101     int now=0,sk=0,qk=1;
    102     for(int i=1;i<=Len;i++){
    103         if(s[i]>='a'&&s[i]<='z'){
    104             now=ch[now][s[i]-'a'];
    105             Add(in[now],1);
    106         }
    107         else if(s[i]=='B'){
    108             Add(in[now],-1);
    109             now=fa[now];
    110         }
    111         else{
    112             sk++;
    113             while(qry[qk].y==sk){
    114                 Ans[qry[qk].idx]=Sum(out[pos[qry[qk].x]])-Sum(in[pos[qry[qk].x]]-1);
    115                 qk++;
    116             }
    117         }
    118     }
    119     for(int i=1;i<=M;i++){
    120         outint(Ans[i]);
    121         putchar('
    ');
    122     }
    123     return 0;
    124 }
  • 相关阅读:
    测试随笔
    ECNU 3530 和你在一起
    ECNU 1030 母牛生小牛
    ECNU 3081 购房还款
    PPP模式下的融资结构优化
    决策树分类
    关联规则-R语言实现
    中国快递包裹总量的预测-基于SARIMA模型
    LeetCode 2 :Swap Nodes in Pairs
    2018092609-2 选题 Scrum立会报告+燃尽图 04
  • 原文地址:https://www.cnblogs.com/halfrot/p/7658060.html
Copyright © 2011-2022 走看看