zoukankan      html  css  js  c++  java
  • BZOJ3413: 匹配(后缀自动机 线段树合并)

    题意

    题目链接

    Sol

    神仙题Orz

    后缀自动机 + 线段树合并。。。

    首先可以转化一下模型(想不到qwq):问题可以转化为统计(B)中每个前缀在(A)中出现的次数。(画一画就出来了)

    然后直接对(A)串建SAM,线段树合并维护一下siz就行了

    #include<bits/stdc++.h>
    using namespace std;
    const int MAXN = 4e5 + 10, SS = 1e7 + 10;
    int N, M;
    char S[MAXN], T[MAXN];
    int fa[MAXN], len[MAXN], ch[MAXN][11], root = 1, las = 1, tot = 1;
    vector<int> par[MAXN];
    int insert(int x) {
    	int now = ++tot, pre = las; las = now; len[now] = len[pre] + 1;
    	for(; pre && !ch[pre][x]; pre = fa[pre]) ch[pre][x] = now;
    	if(!pre) fa[now] = root;
    	else {
    		int q = ch[pre][x];
    		if(len[pre] + 1 == len[q]) fa[now] = q;
    		else {
    			int nq = ++tot; fa[nq] = fa[q]; len[nq] = len[pre] + 1;
    			memcpy(ch[nq], ch[q], sizeof(ch[q]));
    			for(; pre && ch[pre][x] == q; pre = fa[pre]) ch[pre][x] = nq;
    			fa[q] = fa[now] = nq;
    		}
    	}
    	return las;
    }
    void Build() {
    	for(int i = 1; i <= tot; i++) par[fa[i]].push_back(i);
    }
    int rt[SS], ls[SS], rs[SS], sum[SS], cnt;
    void update(int k) {
    	sum[k] = sum[ls[k]] + sum[rs[k]];
    }
    void Modify(int &k, int l, int r, int p, int v) {
    	if(!k) k = ++cnt;
    	if(l == r) {sum[k]++; return ;}
    	int mid = l + r >> 1;
    	if(p <= mid) Modify(ls[k], l, mid, p, v);
    	else Modify(rs[k], mid + 1, r, p, v);
    	update(k);
    }
    int Merge(int x, int y) {
    	if(!x || !y) return x ^ y;
    	int nw = ++cnt;
    	if(!ls[x] && !rs[x]) {sum[nw] = sum[x] + sum[y]; return nw;}
    	ls[nw] = Merge(ls[x], ls[y]);
    	rs[nw] = Merge(rs[x], rs[y]);
    	update(nw);
    	return nw;
    }
    int Get(int k, int l, int r) {
    	if(!k) return N;
    	if(l == r) return l;
    	int mid = l + r >> 1;
    	if(sum[ls[k]]) return Get(ls[k], l, mid);
    	else return Get(rs[k], mid + 1, r);
    }
    int Query(int k, int l, int r, int ql, int qr) {
    	if(!k || (l > r) || (ql > qr)) return 0;
    	if(ql <= l && r <= qr) 
    		return sum[k];
    	int mid = l + r >> 1;
    	if(ql > mid) return Query(rs[k], mid + 1, r, ql, qr);
    	else if(qr <= mid) return Query(ls[k], l, mid, ql, qr);
    	else return Query(ls[k], l, mid, ql, qr) + Query(rs[k], mid + 1, r, ql, qr);
    }
    void dfs(int x) {
    	for(auto &to : par[x]) {
    		dfs(to);
    		rt[x] = Merge(rt[x], rt[to]);
    	}
    }
    void solve() {
    	int n = strlen(T + 1), now = root, flag = 0, Lim = 0;
    	for(int i = 1; i <= n; i++) {
    		int nxt = T[i] - '0';
    		if(!ch[now][nxt]) {flag = 1; break;}
    		now = ch[now][nxt];
    		if(i == n) 
    			Lim = Get(rt[now], 1, N) - n;//µÚÒ»´Î³öÏÖµÄλÖà 
    	}
    	int ans = 0;
    	if(flag) ans = N;
    	else ans = Lim + n;
    	now = root;
    	for(int i = 1; i <= n; i++) {
    		int nxt = T[i] - '0';
    		if(!ch[now][nxt]) break;
    		now = ch[now][nxt];
    		if(flag) ans += Query(rt[now], 1, N, 1, N);
    		else ans += Query(rt[now], 1, N, 1, Lim + i - 1);
    	}
    	cout << ans << '
    ';
    }
    int main() {
    	//freopen("1.in", "r", stdin); freopen("b.out", "w", stdout);
    	cin >> N;
    	scanf("%s", S + 1);
    	for(int i = 1; i <= N; i++) 
    		Modify(rt[insert(S[i] - '0')], 1, N, i, 1);
    	Build();
    	dfs(root);
    	cin >> M;
    	for(int i = 1; i <= M; i++) {
    		scanf("%s", T + 1);
    		solve();
    	}
    	return 0;
    }
    /*
    7
    1090901
    4
    0901
    87650
    109
    090
    */
    
  • 相关阅读:
    软工实践练习一——使用Git进行代码管理心得
    作业1.3——Android平台的开发环境的发展演变
    作业1.2——软件工程的实践项目的自我目标
    SVN冲突解决
    sea.js及三种加载方式的异同
    php中AJAX请求中使用post和get请求的区别
    Vue-起步篇:Vue与React、 Angular的区别
    页面常见布局以及实现方法--flex
    requestAnimationFrame之缓动的应用
    bootstrap中table页面做省市区级联效果(级联库见前面级联编辑)(非select下拉框)
  • 原文地址:https://www.cnblogs.com/zwfymqz/p/10409186.html
Copyright © 2011-2022 走看看