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 ;
}