您的位置:首页 > 其它

bzoj2434: [Noi2011]阿狸的打字机 trie+线段树

2015-07-13 10:55 344 查看
我们可以先按题目描述建出一个trie树,然后得到fall树,我们可以发现,fall树的子树里有#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
using namespace std;
#define maxn 110000
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define getmid int mid=(l+r)>>1
int sum[maxn*8];
void pushup(int rt)
{
sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void add(int l,int r,int rt,int pos,int v)
{
if(l==r)
{
sum[rt]+=v;
return;
}
getmid;
if(pos<=mid) add(lson,pos,v);
else add(rson,pos,v);
pushup(rt);
}
int qsum(int l,int r,int rt,int x,int y)
{
if(x<=l&&r<=y)
{
return sum[rt];
}
getmid;
int res=0;
if(x<=mid) res+=qsum(lson,x,y);
if(y>mid) res+=qsum(rson,x,y);
return res;
}
int a[maxn][26],n,m,cnt=1,fa[maxn],point[maxn],pos[maxn];
char st[maxn];
int read()
{
char c;int res;
while(c=getchar(),c<'0'||c>'9');
res=c-'0';
while(c=getchar(),c>='0'&&c<='9')
res=res*10+c-'0';
return res;
}
void build()
{
for(int i=0;i<26;i++)
{
a[0][i]=1;
}
n=strlen(st+1);
int now=1,id=0;
for(int i=1;i<=n;i++)
{
if(st[i]=='P')
{
id++;
pos[id]=now;
}
else if(st[i]=='B') now=fa[now];
else
{
if(!a[now][st[i]-'a'])
{
cnt++;
a[now][st[i]-'a']=cnt;
fa[cnt]=now;
}
now=a[now][st[i]-'a'];
}
}
}
int q[maxn];
void acm()
{
int head=0,tail=0;
tail++;q[1]=1;
point[1]=0;
while(head<tail)
{
head++;
int now=q[head];
for(int i=0;i<26;i++)
{
if(!a[now][i]) continue;
int k=point[now];
while(!a[k][i]) k=point[k];
point[a[now][i]]=a[k][i];
tail++; q[tail]=a[now][i];
}
}
}
int en,first[maxn],next[maxn],to[maxn],ind;
void adde(int a,int b)
{
en++;
to[en]=b;next[en]=first[a];
first[a]=en;
}
int in[maxn],out[maxn];
void dfs(int x)
{
ind++;
in[x]=ind;
for(int i=first[x];i;i=next[i])
{
dfs(to[i]);
}
ind++;
out[x]=ind;
}
struct node
{
int to,next,v;
}que[100005];
int last[maxn],ans[maxn];
void solve()
{
add(1,cnt*2,1,in[0],1);
int now=1,id=0;
for(int i=1;i<=n;i++)
{
if(st[i]=='P')
{
id++;
for(int x=last[id];x;x=que[x].next)
{
int v=pos[que[x].to];
ans[x]=qsum(1,cnt*2,1,in[v],out[v]);
}
}
else if(st[i]=='B')
{
add(1,cnt*2,1,in[now],-1);
now=fa[now];
}
else
{
now=a[now][st[i]-'a'];
add(1,cnt*2,1,in[now],1);
}
}
}
int main()
{
scanf("%s",st+1);
build();
acm();
for(int i=1;i<=cnt;i++)
{
adde(point[i],i);
}
dfs(0);
m=read();
for(int i=1;i<=m;i++)
{
int x=read(),y=read();
que[i].next=last[y];
last[y]=i;
que[i].to=x;
}
solve();
for(int i=1;i<=m;i++)
{
printf("%d\n",ans[i]);
}
return 0;
}

几个节点,那么这个串就出现了多少次,由于是棵树,我们可以用的dfs序来维护。考虑在线维护的话,返回到历史k十分麻烦,只能用离线处理。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: