• 离线建AC自动机维护子串+线段树维护AC自动机:HDU4117


    https://acm.hdu.edu.cn/showproblem.php?pid=4117

    离线处理

    AC自动机每次插入都要重构,但其实可以先离线建好,再进行操作

    AC自动机理解——维护子串

    每个子串都可以表示成一个前缀的一个后缀。

    任意一个前缀是Trie树上的一个点,然后其对应后缀就是fail树上的祖先

    fail树本质是一个后缀树

    线段树维护

    现在在fail树上操作,对每个点查询all祖先,可以变成祖先修改时对其所有儿子进行修改、

    维护出每个点的dfs序,然后拿个线段树维护即可

    #include 
    #include 
    #include
    using namespace std;
    //#define int long long
    inline int read(){int x=0,f=1;char ch=getchar(); while(ch<'0'||
    ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){
    x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;}
    #define Z(x) (x)*(x)
    #define pb push_back
    //mt19937 rand(time(0));
    //mt19937_64 rand(time(0));
    //srand(time(0));
    #define N 20010
    #define M 300010
    //#define mo
    int n, m, i, j, k, T, T0;
    int nxt[M][26], fail[M], tot; 
    short dfn[M], len[M], lst[M], p[M]; 
    int rt, u, v, w[N], ans, f; 
    char str[M]; 
    int q[M], l, r; 
    vector<int>G[M]; 
    
    int mx[N<<3]; 
    void add(int k, int l, int r, int x, int y, int z) {
    	if(l>=x && r<=y) return mx[k]=max(mx[k], z), void(); 
    	int m=(l+r)>>1; 
    	if(x<=m) add(k<<1, l, m, x, y, z); 
    	if(y>=m+1) add(k<<1|1, m+1, r, x, y, z); 
    }
    int que(int k, int l, int r, int x) {
    	if(l==r) return mx[k]; 
    	int m=(l+r)>>1; 
    	if(x<=m) return max(mx[k], que(k<<1, l, m, x)); 
    	else return max(mx[k], que(k<<1|1, m+1, r, x)); 
    }
    void clear(int k, int l, int r) {
    	mx[k]=0; 
    	if(l==r) return ; 
    	int m=(l+r)>>1; 
    	clear(k<<1, l, m); clear(k<<1|1, m+1, r); 
    }
    
    void init() {
    	rt=u=v=tot=ans=l=r=0; 
    }
    
    void Trie(int u, int i) {
    	if(!str[i]) return dfn[u]=lst[u]=1, void(); 
    	int c=str[i]-'a'; p[u]=1; 
    	if(!nxt[u][c]) nxt[u][c]=++tot; 
    	Trie(nxt[u][c], i+1); 
    }
    
    void bfs() {
    	memset(fail, 0, sizeof(fail)); 
    	q[++r]=1; fail[1]=0; 
    	while(l<r) {
    		u=q[++l]; 
    		if(!p[u]) continue; 
    		for(int i=0; i<26; ++i) 
    			if(nxt[u][i]) {
    				v=nxt[u][i]; k=fail[u]; 
    				while(k && p[k] && !nxt[k][i]) k=fail[k]; 
    				if(p[k] && nxt[k][i]) fail[v]=nxt[k][i]; 
    				else fail[v]=1; 
    				q[++r]=v; 
    			}
    	}
    }
    
    void dfs(int x) {
    	if(dfn[x]) ++m; dfn[x]=m; 
    	for(int y : G[x]) dfs(y); 
    	if(lst[x]) lst[x]=m, ++m; 
    	else lst[x]=m; 
    }
    
    signed main()
    {
    //	freopen("in.txt", "r", stdin);
    //	freopen("out.txt", "w", stdout);
    	T=read();
    	for(T0=1; T0<=T; ++T0) {
    		init(); 
    		n=read(); rt=tot=1; 
    		for(i=1; i<=n; ++i) {
    			scanf("%s", str+len[i-1]+1); w[i]=read(); 
    			len[i]=strlen(str+len[i-1]+1)+len[i-1]; 
    			Trie(rt, len[i-1]+1); 
    		}
    		bfs(); 
    		for(i=2; i<=tot; ++i) G[fail[i]].pb(i); 
    		m=1; dfs(1);  
    		for(i=1; i<=n; ++i) {
    			f=w[i]; 
    			for(j=len[i-1]+1, u=1; j<=len[i]; ++j) {
    				u=nxt[u][str[j]-'a']; 
    				f=max(f, que(1, 1, m, dfn[u])+w[i]); 
    			}
    			ans=max(ans, f); add(1, 1, m, dfn[u], lst[u], f); 			
    		}
    		clear(1, 1, m); 
    		for(i=1; i<=tot; ++i) {
    			if(p[i]) memset(nxt[i], 0, sizeof(nxt[i]));
    			fail[i]=dfn[i]=lst[i]=p[i]=0; G[i].clear(); 
    		}
    		printf("Case #%d: %d\n", T0, ans); 
    	}
    
    	return 0;
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
  • 相关阅读:
    【C++ Exceptions】Catch exceptions by reference!
    Spring Cloud微服务核心架构分析
    外包干了3个多月,技术退步明显。。。。
    MySQL-函数
    店外营销吸睛,店内体验升级丨餐饮品牌如何「吃」透数据?
    Linux由hello.c生成a.out整个过程
    uniapp-轮播图点击预览功能
    GOM跟GEE登陆器列表文件加密教程
    一次Django SSO简单实现
    【技巧】各编辑器基础开发快捷键
  • 原文地址:https://blog.csdn.net/zhangtingxiqwq/article/details/132804430