[二进制分组 AC自动机] HDU 4787 GRE Words Revenge

这个如果单次询问的话应该是个AC自动机裸题
多次询问本来可以按时间分治
但是强制在线
就可以用xhr的二进制分组方法 浅谈数据结构题的几个非经典解法
也可以看CA的博客 【从此不怕强制在线】二进制分组学习笔记
大致思想是修改按二进制分组 这样最多log组 每次询问的复杂度会多一个log 合并的均摊复杂度也是log的

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<string>
#include<Set>
#include<queue>
#define cl(x) memset(x,0,sizeof(x))
using namespace std;

inline char nc(){
  static char buf[100000],*p1=buf,*p2=buf;
  if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
  return *p1++;
}
inline void read(int &x){
  char c=nc(),b=1;
  for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
  for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}
inline int read(char *s){
  char c=nc(); int len=0;
  for (;!(c>='0' && c<='1');c=nc()) if (c==EOF) return 0;
  for (;c>='0' && c<='1';s[++len]=c,c=nc()); s[++len]=0; return len-1;
}
inline void read(char &x){
  for (x=nc();x!='+' && x!='?';x=nc());
}

typedef long long ll;

const int K=30;
const int N=200005;

int ch[N][2],cnt[N],fail[N];
int ncnt;

string str[N]; int scnt;
set<string> Set;

int root[K],size[K],tot;

inline void Init(){ ncnt=scnt=tot=0; cl(root); cl(size); Set.clear(); }
inline int newnode(){ return (++ncnt,ch[ncnt][0]=ch[ncnt][1]=cnt[ncnt]=fail[ncnt]=0),ncnt; }

queue<int> Q;
inline void Build(int x){
  fail[x]=x; int u,v;
  for (int i=0;i<2;i++)
    if (!ch[x][i])
      ch[x][i]=x;
    else
      fail[ch[x][i]]=x,Q.push(ch[x][i]);
  while(!Q.empty()){
    u=Q.front(); Q.pop();
    for (int i=0;i<2;i++)
      if (!ch[u][i])
    ch[u][i]=ch[fail[u]][i];
      else
    v=ch[u][i],fail[v]=ch[fail[u]][i],cnt[v]+=cnt[fail[v]],Q.push(v);
  }
}

inline void Insert(char *s){
  if (Set.count(s+1)) return;
  Set.insert(s+1); str[++scnt]=string(s+1);

  size[++tot]=1;
  while (tot>1 && size[tot]==size[tot-1]) size[--tot]*=2,ncnt=root[tot]-1;

  root[tot]=newnode();
  for(int i=scnt-size[tot]+1;i<=scnt;i++){
    int p=root[tot];
    for (int j=0;j<str[i].length();j++){
      int x=str[i][j]-'0';
      if (!ch[p][x]) ch[p][x]=newnode();
      p=ch[p][x];
    }
    cnt[p]++;
  }
  Build(root[tot]);
}

inline ll Query(char *s){
  ll ret=0;
  for(int i=1;i<=tot;i++){
    int p=root[i];
    for(int j=1;s[j];j++)
      p=ch[p][s[j]-'0'],ret+=cnt[p];
  }
  return ret;
}

char tmp[5000005],S[5000005];

int main(){
  ll lastans; int T,Q,Case=0,len; char order;
  freopen("t.in","r",stdin);
  freopen("t.out","w",stdout);
  read(T);
  while (T--){
    printf("Case #%d:\n",++Case);
    lastans=0; Init();
    read(Q);
    while (Q--){
      read(order);
      int len=read(tmp);
      for (int i=1;i<=len;i++) S[i]=tmp[(i+lastans-1)%len+1]; S[len+1]=0;
      if (order=='+')
    Insert(S);
      else
    printf("%lld\n",lastans=Query(S));
    }
  }
  return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值