zoukankan      html  css  js  c++  java
  • 【CF163E】e-Government

    题目

    题目链接:https://codeforces.com/problemset/problem/163/E
    给定包含 (n) 个字符串的集合 (S),有 (m) 个操作,操作有三种类型:

    • ? 开头的操作为询问操作,询问当前字符串集 (S) 中的每一个字符串匹配询问字符串的次数之和;
    • + 开头的操作为添加操作,表示将编号为 (i) 的字符串加入到集合中;
    • - 开头的操作为删除操作,表示将编号为 (i) 的字符串从集合中删除。

    注意当编号为 (i) 的字符串已经在集合中时,允许存在添加编号为 (i) 的字符串,删除亦然。
    (n,mleq 10^5,sum |s_i|leq 10^6)

    思路

    (n) 个字符串都扔进一个 AC 自动机里。我们知道计算 (t) 串在 (s) 串中的出现次数,可以在 AC 自动机上不断匹配 (S) 串,对于 (S) 串每一个后缀,找 fail 树上它的祖先是否有 (t) 串结尾所表示的点。
    那么如果添加了 (t) 串进集合,等价于让 (t) 串结尾所表示节点,在 fail 树上的子树全部多了一次匹配。
    那么只需要将 fail 树的 dfs 序求出来,然后树状数组维护区间加,单点查询即可。
    时间复杂度 (O(mlog (sum |S_i|)))

    代码

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    const int N=100010,M=1000010;
    int n,m,lim,ed[N],id[M],siz[M];
    bool vis[N];
    char s[M];
    
    struct BIT
    {
    	ll c[M];
    	
    	void add(int x,ll v)
    	{
    		for (int i=x;i<=lim;i+=i&-i)
    			c[i]+=v;
    	}
    	
    	ll query(int x)
    	{
    		ll ans=0;
    		for (int i=x;i;i-=i&-i)
    			ans+=c[i];
    		return ans;
    	}
    }bit;
    
    struct ACA
    {
    	int tot,fa[M],fail[M],ch[M][26];
    	vector<int> e[M];
    	
    	void insert(char *s,int j,int st=1)
    	{
    		int p=0,len=strlen(s+1);
    		for (int i=st;i<=len;i++)
    		{
    			if (!ch[p][s[i]-'a'])
    				ch[p][s[i]-'a']=++tot,fa[tot]=p;
    			p=ch[p][s[i]-'a'];
    		}
    		ed[j]=p;
    	}
    	
    	void build()
    	{
    		queue<int> q;
    		for (int i=0;i<26;i++)
    			if (ch[0][i]) q.push(ch[0][i]);
    		while (q.size())
    		{
    			int u=q.front(); q.pop();
    			e[fail[u]].push_back(u);
    			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];
    		}
    	}
    	
    	void dfs(int x)
    	{
    		id[x]=++tot; siz[x]=1;
    		for (int i=0;i<e[x].size();i++)
    		{
    			int v=e[x][i];
    			dfs(v); siz[x]+=siz[v];
    		}
    	}
    	
    	void query(char *s)
    	{
    		int len=strlen(s+1),p=0;
    		ll ans=0;
    		for (int i=2;i<=len;i++)
    		{
    			p=ch[p][s[i]-'a'];
    			ans+=bit.query(id[p]);
    		}
    		cout<<ans<<"
    ";
    	}
    }AC;
    
    int main()
    {
    	scanf("%d%d",&m,&n);
    	for (int i=1;i<=n;i++)
    	{
    		scanf("%s",s+1);
    		AC.insert(s,i);
    	}
    	AC.build();
    	AC.tot=0; AC.dfs(0);
    	lim=AC.tot;
    	for (int i=1;i<=n;i++)
    	{
    		vis[i]=1;
    		bit.add(id[ed[i]],1);
    		bit.add(id[ed[i]]+siz[ed[i]],-1);
    	}
    	for (int i=1;i<=m;i++)
    	{
    		scanf("%s",s+1);
    		int len=strlen(s+1);
    		if (s[1]=='?') AC.query(s);
    		if (s[1]=='+')
    		{
    			int x=0;
    			for (int j=2;j<=len;j++)
    				x=x*10+s[j]-48;
    			if (!vis[x])
    			{
    				vis[x]=1;
    				bit.add(id[ed[x]],1);
    				bit.add(id[ed[x]]+siz[ed[x]],-1);
    			}
    		}
    		if (s[1]=='-')
    		{
    			int x=0;
    			for (int j=2;j<=len;j++)
    				x=x*10+s[j]-48;
    			if (vis[x])
    			{
    				vis[x]=0;
    				bit.add(id[ed[x]],-1);
    				bit.add(id[ed[x]]+siz[ed[x]],1);
    			}
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    手动创建分区以及软硬raid的问题
    实用小工具:VNC的安装
    安装使用xen虚拟化工具
    使用vsftp与shell实现对进程与服务状态的监控
    windows server2008下搭建ftp服务
    业界虚拟化技术分析
    Android命名规范(自定义)
    Android Paint和Color类
    Android 应用中十大常见 UX 错误
    漫谈互联网产品设计之人性的弱点,你躺枪了木有?
  • 原文地址:https://www.cnblogs.com/stoorz/p/15036338.html
Copyright © 2011-2022 走看看