2017.8.15 阿狸的打字机 失败总结

        好难啊,这个题需要很强的技巧和码力

        首先ac自动机不难想到,暴力跳fail也不难想到,但建fail树没想到

        建好之后问题就变成了随着点的加入,求一个子树里1的个数

        然后由于询问一定在一个子树里,而加点的时候合法的一定在内部(dfs序内部),所以差分即可求一段中1的和,可用树状数组加速

     


    码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<vector>
using namespace std;
#define N 200010
int sz=1,T=1,len,t[N],i,x,y,l[N],r[N],ch[N][27],ans[N],ci[N],fu[N],sp[N],m;
char str[N];
queue<int>q;
vector<int>v[100005],wen[100005],id[100005];
int lowbit(int a)
{
	return a&(-a);
}

void add(int x,int y)
{	int i;
	for(i=x;i<=T;i+=lowbit(i))
	{
       t[i]+=y;
	}	
}
int qiu(int x)
{
	int ans=0,i;
	for(i=x;i>0;i-=lowbit(i))
	{
		ans+=t[i];
	}	
	return ans;
}
void jia()
{
	int i,o=1,lin=0;
for(i=0;i<len;i++)
if(str[i]=='P')
  ci[++lin]=o;else
if(str[i]=='B')
  o=fu[o];else	
{
	if(ch[o][str[i]-'a'+1]==0)ch[o][str[i]-'a'+1]=++sz,fu[sz]=o;
	o=ch[o][str[i]-'a'+1];
}	
}
void shipei()
{
	int i;
	q.push(1);
	while(!q.empty())
	{
		int st=q.front();
		q.pop();
		for(i=1;i<=26;i++)
		{
			if(ch[st][i]==0)continue;
			int k=sp[st];
			while(ch[k][i]==0)k=sp[k];
			sp[ch[st][i]]=ch[k][i];
			q.push(ch[st][i]);
		}
	}
}
void dfs(int o)
{
	l[o]=++T;
	for(int i=0;i<v[o].size();i++)
	dfs(v[o][i]);
	r[o]=++T;	
}
void work()
{
	int o=1,dc=0;
	add(l[1],1);
	for(int j=0;j<len;j++)
	if(str[j]=='P')
	{
		++dc;
		for(i=0;i<wen[dc].size();i++)
		{
		int x=ci[wen[dc][i]];
		ans[id[dc][i]]=qiu(r[x])-qiu(l[x]-1);
		}
		
	}else if(str[j]=='B')add(l[o],-1),o=fu[o];
	else{
		o=ch[o][str[j]-'a'+1];
		add(l[o],1);
	}
}
int main()
{
	
	for(i=1;i<=26;i++)
      ch[0][i]=1;     
      scanf("%s",str);	len=strlen(str);
    jia();shipei();
    for(i=1;i<=sz;i++)
    v[sp[i]].push_back(i);
	scanf("%d",&m);
	for(i=1;i<=m;i++)
	{
		scanf("%d%d",&x,&y);
		wen[y].push_back(x);
		id[y].push_back(i);
	}
	dfs(1);
	work();	
	for(i=1;i<=m;i++)
	printf("%d\n",ans[i]);
} 


       

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值