BZOJ 2434 [Noi2011]阿狸的打字机

题目大意:

先以特定模式按顺序给出了N个单词,给出M个二元组(x,y)询问:给出的第x个单词在第y个单词中出现了几次。(N,M<=10^5)

解题思路:

1、建立ac自动机的过程就不在赘述。

2、首先需要了解或者发现fail树,fail树是指AC自动机上由fail链构成的树。由于每个状态点入度为一,且根据BFS的构造两点的深度满足递增关系,因此不会出现环,从而是一棵树。

3、fail树具有如下性质:在某一点沿着fail树走向根,将遍历所有以该点至Trie根这一字符串的后缀为前缀的单词所对应的前缀最后一个字符节点位置。
4、因此如果将y单词的所有节点标记为1,那么x在y中出现的次数就是fail树中以x终止节点为根的子树中1的个数。

5、子树统计问题常用DFS序列转化为区间统计问题。大规模询问可以通过离线重新组织询问次序使得更方便快捷求解。于是我们将对y做邻接表,链出所有询问x,离线处理。

6、这样我们沿着AC自动机的Trie树DFS,每到一个节点将他的DFS序在树状数组中加1,如果是y对应的节点,处理所有询问x就是统计对应x的fail子树1的个数,递归结束返回前再将他的DFS序在树状数组中减1。问题就得到解决。


/**************************************************************
    Problem: 2434
    User: xushu
    Language: C++
    Result: Accepted
    Time:600 ms
    Memory:30404 kb
****************************************************************/
 
#include <iostream>
#include <cstdio>
#include <cstdio>
#include <queue>
#include <cstring>
using namespace std;
const int maxs=1e5+100;
char s[maxs];
int ans[maxs];
 
struct tree_edge{
int e[maxs],nex[maxs],cnt,head[maxs];
void init(int n){ cnt=0;for (int i=0;i<=n;i++) head[i]=-1;}
void add_edge(int x,int y){
  e[cnt]=y;nex[cnt]=head[x];head[x]=cnt++;
}
} ted;
 
struct question{
struct node{
  int y,num;
}    ;
node e[maxs];
int nex[maxs],cnt,head[maxs];
void init(int n){ cnt=0;for (int i=0;i<=n;i++) head[i]=-1;}
void add_edge(int x,int y,int i){
  e[cnt]=(node){y,i};nex[cnt]=head[x];head[x]=cnt++;
}
} que;
 
struct acauto{
   int cnt,ch[maxs][26],fa[maxs],f[maxs],val[maxs],id,adr[maxs],och[maxs][26];
   int last[maxs];
   int l;
   int idx(char x) {return x-'a';}
   void init(){
     cnt=0;
     memset(ch[0],0,sizeof(ch[0]));
     memset(och[0],0,sizeof(och[0]));
     f[0]=id=0;
   }
   int newnode(){
      cnt++;
      memset(och[cnt],0,sizeof(och[cnt]));
      memset(ch[cnt],0,sizeof(ch[cnt]));
      return cnt;
   }
 
   void solve(){
     int i,v,u;
     l=strlen(s);
     for (i=0;i<l;i++) val[i]=0;
     u=0;i=0;
     while (i<l){
       if (s[i]=='P') {
        if (val[u]) {
            adr[++id]=u;
        } else {
           val[u]=++id;
           adr[id]=u;
        }
        i++;continue;
       }
 
       if (s[i]=='B') {
         if (u) u=fa[u];
         i++;
         continue;
       }
 
       v=idx(s[i]);
       if (ch[u][v]) u=ch[u][v],i++;
       else {
        och[u][v]=ch[u][v]=newnode();
        fa[ch[u][v]]=u;
        u=ch[u][v];i++;
       }
     }
   }
 
   void get_fail(){
     queue<int> q;
     int i,u;
     for (i=0;i<26;i++) if (ch[0][i]) {f[ch[0][i]]=0;q.push(ch[0][i]);ted.add_edge(0,ch[0][i]);last[ch[0][i]]=0;}
     while (!q.empty()){
        int r=q.front();q.pop();
        for (i=0;i<26;i++){
           u=ch[r][i];
           if (!u){ ch[r][i]=ch[f[r]][i];continue;}
           f[u]=ch[f[r]][i];
           ted.add_edge(ch[f[r]][i],u);
           last[u]=val[f[u]] ? f[u]:last[f[u]];
           q.push(u);
        }
     }
   }
 
};
 
struct Fenwick{
  int c[2*maxs],n;
  void init(){for (int i=0;i<=n;i++) c[i]=0;}
  int lowbit(int x) {return x&(-x);}
  void add(int i,int x){
     while (i<=n){
        c[i]+=x;
        i+=lowbit(i);
     }
  }
 
  int sum(int i){
    int ans=0;
    while (i>0){
      ans+=c[i];
      i-=lowbit(i);
    }
    return ans;
  }
} ;
 
 
 
Fenwick fk;
acauto ac;
int did;
int l[maxs],r[maxs];
void dfs_id(int u){
   l[u]=++did;
   for (int i=ted.head[u];i!=-1;i=ted.nex[i]){
        dfs_id(ted.e[i]);
   }
   r[u]=++did;
}
 
void dfs(int u){
  int i,v,now;
  fk.add(l[u],1);
 
  for (i=que.head[u];i!=-1;i=que.nex[i]){
    v=que.e[i].num;
    now=que.e[i].y;
    ans[v]=fk.sum(r[now])-fk.sum(l[now]-1);
  }
 
  for (i=0;i<26;i++){
    if (!ac.och[u][i]) continue;
    dfs(ac.och[u][i]);
  }
  fk.add(l[u],-1);
}
 
int main()
{
    int m;
    int x,y;
    scanf("%s",s);
    int ll=strlen(s);
    ted.init(ll);
    ac.init();
    ac.solve();
    ac.get_fail();
    did=0;
    dfs_id(0);
 
 
    scanf("%d",&m);
    que.init(ll);
    for (int k=1;k<=m;k++){
        scanf("%d %d",&x,&y);
        x=ac.adr[x];y=ac.adr[y];
        que.add_edge(y,x,k);
    }
 
    fk.n=did;
    fk.init();
    dfs(0);
    for (int k=1;k<=m;k++) printf("%d\n",ans[k]);
    return 0;
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
智慧校园的建设目标是通过数据整合、全面共享,实现校园内教学、科研、管理、服务流程的数字化、信息化、智能化和多媒体化,以提高资源利用率和管理效率,确保校园安全。 智慧校园的建设思路包括构建统一支撑平台、建立完善管理体系、大数据辅助决策和建设校园智慧环境。通过云架构的数据中心与智慧的学习、办公环境,实现日常教学活动、资源建设情况、学业水平情况的全面统计和分析,为决策提供辅助。此外,智慧校园还涵盖了多媒体教学、智慧录播、电子图书馆、VR教室等多种教学模式,以及校园网络、智慧班牌、校园广播等教务管理功能,旨在提升教学品质和管理水平。 智慧校园的详细方案设计进一步细化了教学、教务、安防和运维等多个方面的应用。例如,在智慧教学领域,通过多媒体教学、智慧录播、电子图书馆等技术,实现教学资源的共享和教学模式的创新。在智慧教务方面,校园网络、考场监控、智慧班牌等系统为校园管理提供了便捷和高效。智慧安防系统包括视频监控、一键报警、阳光厨房等,确保校园安全。智慧运维则通过综合管理平台、设备管理、能效管理和资产管理,实现校园设施的智能化管理。 智慧校园的优势和价值体现在个性化互动的智慧教学、协同高效的校园管理、无处不在的校园学习、全面感知的校园环境和轻松便捷的校园生活等方面。通过智慧校园的建设,可以促进教育资源的均衡化,提高教育质量和管理效率,同时保障校园安全和提升师生的学习体验。 总之,智慧校园解决方案通过整合现代信息技术,如云计算、大数据、物联网和人工智能,为教育行业带来了革命性的变革。它不仅提高了教育的质量和效率,还为师生创造了一个更加安全、便捷和富有智慧的学习与生活环境。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值