zoukankan      html  css  js  c++  java
  • cf710F. String Set Queries

    题解:  我们考虑到 对于一个AC自动机而言 建好fair指针后 不能再插入字符串并维护fair指针 所以我们考虑暴力的做法 在加入字符串的同时 并重新构造fair指针  这样的复杂度是接受不了的  因为对于一个字符串而言他会被操作n次 我们考虑到一个优化是说 对于第一个插入的字符串我们没必要一直在后面的操作中重构它 我们想到用2进制加法这样优化构造过程 类似的  对于每一次进位 考虑进位的这个位置是否有trie树 若没有则在这个位置构造Fair  否则继续进位 到没有为止  这样保证了每个字符串只会被操作logn次 复杂度得到保证

    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <vector>
    #include <stack>
    #include <queue>
    #include <cmath>
    #include <set>
    #include <map>
    #define mp make_pair
    #define pb push_back
    #define pii pair<int,int>
    #define inc(i,l,r) for(int i=l;i<=r;i++)
    #define dec(i,r,l) for(int i=r;i>=l;i--)
    const int MAXN=3e5+10;
    const double eps=1e-8;
    #define ll long long
    using namespace std;
    ll read(){
        ll x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
        while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
        return x*f;
    }
    typedef struct AC{
        int fair[MAXN],ch[MAXN][26],st[MAXN],tot=0,sum[MAXN],cnt=0,rt[21],key[MAXN];
        queue<int>que;
        AC(){
    	inc(i,0,20)rt[i]=0;
        }
        void newnode(int &x){
    	if(tot)x=st[tot--];
    	else x=++cnt;
    	fair[x]=sum[x]=key[x]=0;
    	inc(i,0,25)ch[x][i]=0;
        }
        void insert(char s[]){
    	newnode(rt[0]);
    	int len=strlen(s);int temp=rt[0];
    	for(int i=0;i<len;i++){
    	    int t=s[i]-'a';
    	    if(!ch[temp][t])newnode(ch[temp][t]);
    	    temp=ch[temp][t];
    	}
    	key[temp]=1;
        }
        void merge(int &x,int y){
    	if(x){sum[x]=fair[x]=0;}
    	if(!y)return ;
    	if(!x){x=y;return ;}
    	st[++tot]=y;key[x]+=key[y];
    	for(int i=0;i<26;i++)merge(ch[x][i],ch[y][i]);
        }
        void Fair(int x){
    	que.push(x);
    	while(!que.empty()){
    	    int t=que.front();que.pop();
    	    for(int i=0;i<26;i++){
    		if(!ch[t][i])continue;
    		if(!fair[t]){fair[ch[t][i]]=x;sum[ch[t][i]]=key[ch[t][i]];que.push(ch[t][i]);continue;}
    		int temp=fair[t];
    		for(;temp&&!ch[temp][i];temp=fair[temp]);
    		if(!temp)fair[ch[t][i]]=x,sum[ch[t][i]]=key[ch[t][i]];
    		else fair[ch[t][i]]=ch[temp][i],sum[ch[t][i]]=sum[ch[temp][i]]+key[ch[t][i]];
    		que.push(ch[t][i]);
    	    }
    	}
        }
        void Insert(char s[]){
    	insert(s);
    	    for(int i=1;i<=20;i++){
    		if(rt[i]){
    		    merge(rt[i],rt[i-1]);rt[i-1]=0;
    		}
    		else{
    		    merge(rt[i],rt[i-1]);rt[i-1]=0;
    		    Fair(rt[i]);
    		    break;
    		}
    	    }
        }
        int querty(char s[]){
    	int len=strlen(s);int ans=0;
    	for(int i=1;i<=20;i++){
    	    if(!rt[i])continue;
    	    int temp=rt[i];
    	    for(int j=0;j<len;j++){
    		int t=s[j]-'a';
    		if(!ch[temp][t]){
    		    int p=temp;
    		    for(;p&&!ch[p][t];p=fair[p]);
    		    if(!p)temp=rt[i];else temp=ch[p][t];
    		}
    		else temp=ch[temp][t];
    		ans+=sum[temp];
    	    }
    	}
    	return ans;
        }
    }AC;
    AC *add,*delet;
    
    char str[MAXN];
    
    int main(){
        int m=read();
        add=new AC();delet=new AC();
        while(m--){
    	int op=read();scanf("%s",str);
    	if(op==1)add->Insert(str);
    	else if(op==2)delet->Insert(str);
    	else printf("%d
    ",add->querty(str)-delet->querty(str));
    	fflush(stdout);
        }
        return 0;
    }
    

     

    F. String Set Queries
    time limit per test
    3 seconds
    memory limit per test
    768 megabytes
    input
    standard input
    output
    standard output

    You should process m queries over a set D of strings. Each query is one of three kinds:

    1. Add a string s to the set D. It is guaranteed that the string s was not added before.
    2. Delete a string s from the set D. It is guaranteed that the string s is in the set D.
    3. For the given string s find the number of occurrences of the strings from the set D. If some string p from D has several occurrences in s you should count all of them.

    Note that you should solve the problem in online mode. It means that you can't read the whole input at once. You can read each query only after writing the answer for the last query of the third type. Use functions fflush in C++ and BufferedWriter.flush in Javalanguages after each writing in your program.

    Input

    The first line contains integer m (1 ≤ m ≤ 3·105) — the number of queries.

    Each of the next m lines contains integer t (1 ≤ t ≤ 3) and nonempty string s — the kind of the query and the string to process. All strings consist of only lowercase English letters.

    The sum of lengths of all strings in the input will not exceed 3·105.

    Output

    For each query of the third kind print the only integer c — the desired number of occurrences in the string s.

    Examples
    input
    Copy
    5
    1 abc
    3 abcabc
    2 abc
    1 aba
    3 abababc
    output
    Copy
    2
    2
    input
    Copy
    10
    1 abc
    1 bcd
    1 abcd
    3 abcd
    2 abcd
    3 abcd
    2 bcd
    3 abcd
    2 abc
    3 abcd
    output
    Copy
    3
    2
    1
    0
  • 相关阅读:
    第二次作业
    大学——新生活方式
    第四次作业
    第三次作业
    第二次作业——起航
    梦开始的地方
    第四次作业
    第三次作业
    第二次作业
    博客作业 随笔
  • 原文地址:https://www.cnblogs.com/wang9897/p/10116791.html
Copyright © 2011-2022 走看看