您的位置:首页 > 其它

BZOJ2434: [Noi2011]阿狸的打字机

2018-02-21 15:50 344 查看
阿狸的打字过程实际上是在建一个trie树,对这棵trie建立ac自动机的fail树后,问第x个串在第y个串中出现了多少次,相当于问y串有多少个前缀,在fail树中位于x的子树里

到这里其实好像离线一下就可以了?但还有另一种资瓷在线询问的做法

我们不可能对y串的每个前缀处理,因为这个trie树的建立可以让所有串的总长是n^2级别的

但其实在trie树上这样走造字符串,很多串有着很长的LCP,比如在t1时刻我从节点x走了下去,在t2时刻退出了节点x,那么t1~t2时刻造出的所有字符串的前缀都有x,我们在trie树上走进一个节点时记录当前在造第x个串,离开时若当前在造第y个串,那么x就是串[x,y)的前缀,x的子树中[x,y)的出现次数就+1,这样得到的区间[x,y)的数量是O(n)个的,对每个点p的[x,y),在p的线段树上对[x,y)区间+1,然后在fail树上线段树合并,就可以求出每个点p的子树内每个串的出现次数,就可以O(log)做到在线询问了

code:

#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;

const int maxn = 210000;

int n,m,to[maxn];
int ans[maxn],qi[maxn];
vector<int>query[maxn];
struct segment
{
int seg[maxn*25],lc[maxn*25],rc[maxn*25],root[maxn],cnt;
int lx,rx;
void add(int &x,const int l,const int r)
{
if(rx<l||r<lx) return;
if(!x) x=++cnt;
if(lx<=l&&r<=rx) { seg[x]++; return; }
int mid=l+r>>1;
add(lc[x],l,mid); add(rc[x],mid+1,r);
}
void merge(int &x,const int y)
{
if(!y) return;
if(!x) { x=y; return; }
seg[x]+=seg[y];
merge(lc[x],lc[y]);
merge(rc[x],rc[y]);
}
int loc,c;
int query(const int x,const int l,const int r)
{
c+=seg[x];
if(l==r||!x) return c;
int mid=l+r>>1;
if(loc<=mid) return query(lc[x],l,mid);
else return query(rc[x],mid+1,r);
}
}seg;
struct interval{int l,r;};
vector<interval>V[maxn];

struct edge{int y,nex;}a[maxn]; int len,fir[maxn];
inline void ins(const int x,const int y){a[++len]=(edge){y,fir[x]};fir[x]=len;}
void dfs(const int x)
{
for(int i=0;i<V[x].size();i++)
{
const interval now=V[x][i];
seg.lx=now.l,seg.rx=now.r-1;
if(seg.lx<=seg.rx) seg.add(seg.root[x],1,n);
}
for(int k=fir[x],y=a[k].y;k;k=a[k].nex,y=a[k].y)
{
dfs(y);
seg.merge(seg.root[x],seg.root[y]);
}
for(int i=0;i<query[x].size();i++)
{
int j=query[x][i],y=qi[j];
seg.loc=y; seg.c=0;
ans[j]=seg.query(seg.root[x],1,n);
}
}

struct trie{int son[26],fa,fail,las;}tr[maxn]; int root,tot;

char str[maxn];
queue<int>q;
void build_trie()
{
int x=root,len=strlen(str); n=1;
for(int i=0;i<len;i++)
{
char cc=str[i];
if(cc=='P') to[++n]=x;
else if(cc=='B') V[x].push_back((interval){tr[x].las,n}),x=tr[x].fa;
else
{
int c=cc-'a';
if(!tr[x].son[c]) tr[tr[x].son[c]=++tot].fa=x;
x=tr[x].son[c]; tr[x].las=n;
}
}
while(1)
{
V[x].push_back((interval){tr[x].las,n});
if(x==root) break;
x=tr[x].fa;
}
q.push(root);
while(!q.empty())
{
const int x=q.front(); q.pop();
int fl=tr[x].fail;
for(int i=0;i<26;i++)
{
int &y=tr[x].son[i];
if(y)
{
if(x!=root) tr[y].fail=tr[fl].son[i];
q.push(y);
}
else y=tr[fl].son[i];
}
}
}
void build_failtree()
{
len=0; //memset(fir,0,sizeof fir);
for(int i=1;i<=tot;i++) ins(tr[i].fail,i);
}

int main()
{
scanf("%s",str);
build_trie();
build_failtree();

scanf("%d",&m);
for(int i=1;i<=m;i++)
{
int x,y; scanf("%d%d",&x,&y);
qi[i]=y;
query[to[x+1]].push_back(i);
}
dfs(0);
for(int i=1;i<=m;i++) printf("%d\n",ans[i]);

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: