bzoj2434: [Noi2011]阿狸的打字机

题目链接

bzoj2434: [Noi2011]阿狸的打字机

题解

建出fail树,如果fail树中只有第y个字符串那就是求x串这个点的子树和
对于每组询问的y分类
我们可以重新进行一次建树一样的操作,每次dfs的到字符串y
只要在fail树上用dfs序+树状数组维护,每次把路径上的点插到bit里

代码

#include<queue> 
#include<vector> 
#include<cstdio> 
#include<cstring> 
#include<algorithm>  

inline int read() { 
	int x = 0,f = 1; 
	char c = getchar(); 
	while(c < '0' || c > '9')c = getchar(); 
	while(c <= '9' && c >= '0') x = x * 10 + c - '0',c = getchar(); 
	return x * f; 
} 

const int maxn = 200007; 

char str[maxn]; 
int lt[maxn],n,ch[maxn][27],fail[maxn]; 
int tot = 0; 
int tmp[maxn][27]; 
void buildfail() { 
	std::queue<int>q; 
	for(int i = 0;i < 26;++ i) if(ch[0][i])q.push(ch[0][i]); 	
	while(!q.empty()) { 
		int u = q.front();q.pop(); 
		for(int i = 0;i < 26;++ i) 
			if(ch[u][i]) { 
				fail[ch[u][i]] = ch[fail[u]][i],q.push(ch[u][i]); 
			} else ch[u][i] = ch[fail[u]][i]; 
	} 	 
} 

struct Query { 
	int x,y,id,ans; 
	bool operator < (const Query&a) const {
		return y < a.y; 
	} 
} q[maxn]; 
int ql[maxn],qr[maxn]; 

std::vector<int>v[maxn]; 
int dfn[maxn],low[maxn]; 
int cnt = 0; 
void dfs(int x ) { 
	dfn[x] = ++ cnt; 
	for(int i = 0;i < v[x].size();++ i) dfs(v[x][i]); 
	low[x] = cnt; 
} 

int bit[maxn]; 
#define lowbit(x) (x & -x) 
void add(int x,int v) { 
	for(;x <= cnt;x += lowbit(x)) bit[x] += v; 
} 
int query(int x,int ret = 0) { 
	for(;x;x -= lowbit(x)) ret += bit[x]; 
	return ret; 
} 
int end[maxn]; 
void DFS(int u) { 
	add(dfn[u],1); 
	if(lt[u]) 
		for(int i = ql[lt[u]];i <= qr[lt[u]];++ i) 
			q[i].ans = query(low[end[q[i].x]]) - query(dfn[end[q[i].x]] - 1); 
	for(int i = 0;i < 26;++ i) 
		if(tmp[u][i]) DFS(tmp[u][i]); 
	add(dfn[u],-1); 
} 
int Ans[maxn]; 
int pre[maxn]; 
int main() { 
	scanf("%s",str + 1); 
	int now = 0; 
	for(int i = 1;str[i];++ i) { 
		if(str[i] >= 'a' && str[i] <= 'z') { 
			int t = str[i] - 'a'; 
			if(!ch[now][t]) ch[now][t] = ++ tot,pre[tot] = now; 
			now = ch[now][t];  
		} 
		if(str[i] == 'B') now = pre[now]; 
		else if(str[i] == 'P') { end[++ n] = now;lt[now] = n;}  
	} 
	for(int i = 0;i <= tot;++ i) for(int j = 0;j < 26;++ j) 
		tmp[i][j] = ch[i][j]; 
	buildfail(); 
	for(int i = 1;i <= tot;++ i)v[fail[i]].push_back(i); 
	dfs(0); 
	int Q = read(); 
	for(int i = 1;i <= Q;++ i) q[i].x = read(),q[i].y = read(),q[i].id = i; 
	std::sort(q + 1,q + Q + 1); 
	for(int pos = 1, i = 1; i <= Q;++ i) { 
		ql[q[i].y] = i; 
		while(q[pos].y == q[i].y) pos ++; 
		qr[q[i].y] = i = pos - 1; 
	} 
	DFS(0); 
	for(int i = 1;i <= Q;++ i) Ans[q[i].id] = q[i].ans; 
	for(int i = 1;i <= Q;++ i) printf("%d\n",Ans[i]); 
	return 0 ; 
} 
posted @ 2018-08-22 21:54  zzzzx  阅读(148)  评论(0编辑  收藏  举报