• bzoj2434 阿狸的打字机


    题目链接

    思路

    可以发现,其实题目中所描述的操作,就是在(AC)自动机上走的过程。输出就是打上标记。删除就是返回父亲节点。
    然后看询问。每次询问字符串(x)在字符串中(y)出现的次数。其实也就是问在(AC)自动机上的(y)这个字符串上,有多少位置的(fail)指针指向(x)的结尾。
    所以想到将(fail)指针反过来,建立(fail)树。
    先考虑只有一次询问的时候怎么做。只要将(AC)自动机上从根到(y)路径上的点在(fail)树上对应的变成(1)。然后询问以(fail)树上以(x)为根的子树有多少个(1)
    对于多次询问,可以将询问离线下来。然后在(AC)自动机上走。当新走到一个点的时候,就在(fail)树上这个点对应的(++)。当删除一个点的时候,就在(fail)树上这个点对应的(--)。当打印字符串的时候。就回答那些(y)为当前字符串的询问。
    这样的单点修改,子树查询可以用(dfs)序+树状数组解决。

    代码

    /*
    * @Author: wxyww
    * @Date:   2019-02-01 10:28:18
    * @Last Modified time: 2019-02-01 16:35:45
    */
    #include<cstdio>
    #include<iostream>
    #include<cstdlib>
    #include<cmath>
    #include<queue>
    #include<ctime>
    #include<cstring>
    #include<algorithm>
    #include<bitset>
    using namespace std;
    typedef long long ll;
    const int N = 100000 + 100;
    ll read() {
    	ll x=0,f=1;char c=getchar();
    	while(c<'0'||c>'9') {
    		if(c=='-') f=-1;
    		c=getchar();
    	}
    	while(c>='0'&&c<='9') {
    		x=x*10+c-'0';
    		c=getchar();
    	}
    	return x*f;
    }
    char s[N];
    int dy[N];
    int trie[N][26];
    int ans[N];
    struct node{
    	int x,y,id;
    }que[N];
    bool cmp(node x,node y) {
    	return x.y < y.y;	
    }
    int tot = 1,n,now = 1;
    int fa[N],bz[N],bzjs;
    void solve() {
    	n = strlen(s + 1);
    	for(int i = 0;i <= 100010;++i) fa[i] = 1;
    	for(int i = 1;i <= n;++i) {
    		if(s[i] == 'P') {
    			bz[now] = ++bzjs;
    			dy[bzjs] = now;
    			continue;
    		}
    		if(s[i] == 'B') {
    			now = fa[now];
    			continue;
    		}
    		int x = s[i] - 'a';
    		if(!trie[now][x]) trie[now][x] = ++tot;
    		fa[trie[now][x]] = now;
    		now = trie[now][x];
    	}
    }
    queue<int>q;
    vector<int>e[N];
    int fail[N];
    void get_fail() {
    	for(int i = 0;i <= tot;++i) fail[i] = 1;
    	for(int i = 0;i < 26;++i) if(trie[1][i]) q.push(trie[1][i]);
    	while(!q.empty()) {
    		int u = q.front();q.pop();
    		for(int i = 0;i < 26;++i) {
    			if(trie[u][i]) fail[trie[u][i]] = trie[fail[u]][i],q.push(trie[u][i]);
    			else trie[u][i] = trie[fail[u]][i];
    		}
    	}
    	for(int i = 2;i <= tot;++i) {
    		if(fail[i] == 0) fail[i] = 1;e[fail[i]].push_back(i);
    	}
    }
    int id[N],cnt,siz[N];
    void dfs(int u) {
    	id[u] = ++cnt;
    	siz[u] = 1;
    	int k = e[u].size();
    	for(int i = 0;i < k;++i) {
    		int v = e[u][i];
    		dfs(v);
    		siz[u] += siz[v];
    	}
    }
    int pos = 1;
    int tree[N];
    void update(int pos,int c) {
    	while(pos <= tot) {
    		tree[pos] += c;
    		pos += pos & -pos;
    	}
    }
    int query(int pos) {
    	int anss = 0;
    	while(pos >= 1) {
    		anss += tree[pos];
    		pos -= pos & -pos;
    	}
    	return anss;
    }
    void work() {
    	now = 1;
    	for(int i = 1;i <= n;++i) {
    		if(s[i] == 'P') {
    			while(que[pos].y == bz[now]) {
    				ans[que[pos].id] = query(id[dy[que[pos].x]] + siz[dy[que[pos].x]] - 1) - query(id[dy[que[pos].x]] - 1);
    				++pos;
    			}
    			continue;
    		}
    		if(s[i] == 'B') {
    			update(id[now],-1);
    			now = fa[now];
    			continue;
    		}
    		int x = s[i] - 'a';
    		now = trie[now][x];
    		update(id[now],1);
    	}
    }
    int main() {
    	scanf("%s",s + 1);
    	int m = read();
    	for(int i = 1;i <= m;++i) {
    		que[i].id = i;
    		que[i].x = read(),que[i].y = read();
    	}
    	sort(que + 1,que + m + 1,cmp);
    	solve();
    	get_fail();
    	dfs(1);
    	work();
    	for(int i = 1;i <= m;++i) printf("%d
    ",ans[i]);
    	return 0;
    }
    
    /*
    aPaPBbP 3 1 2 1 3 2 3
    
    */
    
  • 相关阅读:
    zookeeper 4 letter 描述与实践
    zookeeper理论
    Zookeeper的功能以及工作原理
    zookeeper
    VMware安装、配置CentOS
    python安装requests (win7 & centos7)
    Centos 6.4 32位 gcc 升级(已验证)
    Centos6.4编译安装Node.js(已验证)
    使用supervisor提高nodejs调试效率 (已验证)
    tar.xz文件如何解压 (已验证)
  • 原文地址:https://www.cnblogs.com/wxyww/p/10346258.html
Copyright © 2020-2023  润新知