阿狸的打字机

orzzw的超短写法.
终于明白fail树是什么意思了-.-
写完交到gfoj无故re,好在cv和bz上都过了.
#include <cstdio>
using namespace std;
const int N=100050;
struct edge {  
	int u,v; edge *nxt;  
	edge (int u,int v,edge *pre): u(u),v(v){nxt=pre;}  
};  
edge *he[N],*qe[N];
int ans[N],ent[N],out[N],cnt;
int fa[N],fail[N],tot;
int id[N],to[N][26],cot;
int q[N];
struct xdt {
	#define mid ((l+r)>>1)
	int a[8*N];
	void add(int t,int l,int r,int x,int k) {
		a[t]+=k;
		if (l==r) return ;
		if (x<=mid) add(t*2,l,mid,x,k); else add(t*2+1,mid+1,r,x,k);
	}
	int  ask(int t,int l,int r,int x,int y) {
		if (x<=l && r<=y) return a[t];
		int ans=0;
		if (x<=mid) ans+=ask(t*2,l,mid,x,y);
		if (y>mid)  ans+=ask(t*2+1,mid+1,r,x,y);
		return ans;
	}
}xdt;
void dfs(int u) {
	ent[u]=++cnt;
	for (edge *i=he[u];i;i=i->nxt) dfs(i->v);
	out[u]=++cnt;
}
void DFS(int u) {
	xdt.add(1,1,cnt,ent[u],1);
	for (edge *i=qe[u];i;i=i->nxt) 
		ans[i->u]=xdt.ask(1,1,cnt,ent[i->v],out[i->v]);
	for (int j=0;j<26;j++) if (to[u][j]) DFS(to[u][j]);
	xdt.add(1,1,cnt,ent[u],-1);
} 
int main() {
	#define nxt to[nw][ch-'a']
	int i,j,n,x,y,l,r,nw; char ch;
	while ((ch=getchar())!='P' && ch!='B' && (ch<'a'||ch>'z')) ;
	for (i=0;i<26;i++) to[0][i]=1;
	for (tot=nw=1;ch=='P' || ch=='B' || (ch>='a' && ch<='z');ch=getchar()) {
		if (ch=='P') id[++cot]=nw; else
		if (ch=='B') nw=fa[nw]; else
		fa[nxt?nxt:nxt=++tot]=nw,nw=nxt;
	}
	for (l=r=q[1]=1;l<=r;l++) 
		for (nw=q[l],i=0;i<26;i++) if (to[nw][i]) {
			for (j=fail[nw];!to[j][i];j=fail[j]) ;
			fail[q[++r]=to[nw][i]]=to[j][i];
		} 
	for (i=1;i<=tot;i++) he[fail[i]]=new edge(fail[i],i,he[fail[i]]);
	for (scanf("%d",&n),i=1;i<=n;i++) {
		scanf("%d%d",&x,&y); x=id[x],y=id[y];
		qe[y]=new edge(i,x,qe[y]);
	}
	dfs(1);
	DFS(1);
	for (i=1;i<=n;i++) printf("%d\n",ans[i]);
} 


阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机打字机上只有 28 28 个按键,分别印有 26 26 个小写英文字母和 B、P 两个字母。经阿狸研究发现,这个打字机是这样工作的: 输入小写字母,打字机的一个凹槽中会加入这个字母(这个字母加在凹槽的最后)。 按一下印有 B 的按键,打字机凹槽中最后一个字母会消失。 按一下印有 P 的按键,打字机会在纸上打印出凹槽中现有的所有字母并换行,但凹槽中的字母不会消失。 例如,阿狸输入 aPaPBbP,纸上被打印的字符如下: a aa ab 我们把纸上打印出来的字符串从 1 1 开始顺序编号,一直到 � n。打字机有一个非常有趣的功能,在打字机中暗藏一个带数字的小键盘,在小键盘上输入两个数 ( � , � ) (x,y)(其中 1 ≤ � , � ≤ � 1≤x,y≤n),打字机会显示第 � x 个打印的字符串在第 � y 个打印的字符串中出现了多少次。 阿狸发现了这个功能以后很兴奋,他想写个程序完成同样的功能,你能帮助他么? 输入格式 输入的第一行包含一个字符串,按阿狸的输入顺序给出所有阿狸输入的字符。 第二行包含一个整数 � m,表示询问个数。 接下来 � m 行描述所有由小键盘输入的询问。其中第 � i 行包含两个整数 � , � x,y,表示第 � i 个询问为 ( � , � ) (x,y)。 输出格式 输出 � m 行,其中第 � i 行包含一个整数,表示第 � i 个询问的答案
06-09
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值