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;
    }
    
  • 相关阅读:
    微信支付开发(12) 认清微信支付v2和v3
    教爸爸妈妈用微信
    微信公众平台开发(103) 四六级成绩查询
    微信支付开发(11) Native支付
    微信公众平台开放设备接入能力
    微信公众平台开发(102) 模板消息
    微信支付开发(10) 全网发布
    微信小店开发(3) 自定义菜单加入维权
    openssl下载
    使用PHP QR Code生成二维码
  • 原文地址:https://www.cnblogs.com/stoorz/p/15036338.html
Copyright © 2011-2022 走看看