zoukankan      html  css  js  c++  java
  • 【BZOJ 3881】【COCI 2015】Divljak

    http://www.lydsy.com/JudgeOnline/problem.php?id=3881
    好难的一道题啊qwq
    一开始我想对T建AC自动机,根本不可做。
    正解是对S建AC自动机。
    fail树的性质:一棵子树中所有的点都有子树的根这个后缀。
    对于要插入的一个串(P_x),我们在AC自动机上匹配它。
    考虑问题要问(S_x)是多少(P_x)的子串,子串可以表示成一个前缀的后缀。
    匹配过程中经过的所有点都可以当做(P_x)的一个前缀,暴力做法是对每个当做(P_x)前缀的点暴力沿着fail指针往上跳,对经过的所有点染上一种颜色。
    回答询问就是回答代表(S_x)的结点有多少不同的颜色。
    对于上面那个暴力做法,可以在每个代表(P_x)前缀的结点上打上颜色,回答询问直接统计子树里有多少种不同的颜色即可。
    可以用bits维护dfs序,但在一棵子树里同一种颜色可能有两个,对这棵子树的dfs序贡献必须是1。
    有一个非常神奇的东西,把当前所有要打上颜色的结点按dfs序排序,每个节点上+1,排序后相邻结点的lca出-1。
    这样对于一棵子树里的所有颜色相同的结点,它们总的贡献是1。
    好神啊,不过(2*10^6)能用(O(nlog n))

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    
    const int N = 2000003;
    
    struct node {int nxt, to;} E[N];
    int id[N], qu[N], ch[N][26], cnt = 0, cnt2 = 1, fail[N], point[N];
    void ins(int u, int v) {E[++cnt] = (node) {point[u], v}; point[u] = cnt;}
    
    void insert(int num, char *s) {
    	int x, tmp = 1, len = strlen(s);
    	for (int i = 0; i < len; ++i) {
    		x = s[i] - 'a';
    		if (ch[tmp][x] != 0) tmp = ch[tmp][x];
    		else tmp = ch[tmp][x] = ++cnt2;
    	}
    	id[num] = tmp;
    }
    
    void BFS() {
    	int p = 0, q = 1, f, x, v; qu[1] = 1;
    	while (p != q) {
    		x = qu[++p];
    		for (int i = 0; i < 26; ++i)
    			if (ch[x][i]) {
    				v = qu[++q] = ch[x][i];
    				f = fail[x];
    				while (f && ch[f][i] == 0)
    					f = fail[f];
    				fail[v] = f ? ch[f][i] : 1;
    				ins(fail[v], v);
    			}
    	}
    }
    
    int tot = 0, n, deep[N], L[N], R[N], sz[N], top[N], son[N], fa[N];
    char s[N];
    
    void dfs(int x) {
    	L[x] = ++tot; sz[x] = 1;
    	for (int i = point[x], v = E[i].to; i; v = E[i = E[i].nxt].to) {
    		fa[v] = x; deep[v] = deep[x] + 1;
    		dfs(v); sz[x] += sz[v];
    		if (son[x] == 0 || sz[v] > sz[son[x]])
    			son[x] = v;
    	}
    	R[x] = tot;
    }
    
    void dfs2(int x) {
    	if (son[x]) {
    		top[son[x]] = top[x];
    		dfs2(son[x]);
    	}
    	for (int i = point[x], v = E[i].to; i; v = E[i = E[i].nxt].to)
    		if (v != son[x])
    			top[v] = v, dfs2(v);
    }
    
    int LCA(int x, int y) {
    	while (top[x] != top[y]) {
    		if (deep[top[x]] < deep[top[y]])
    			swap(x, y);
    		x = fa[top[x]];
    	}
    	return deep[x] < deep[y] ? x : y;
    }
    
    bool cmp(int x, int y) {return L[x] < L[y];}
    int bits[N], a[N];
    
    void update(int x, int d) {
    	for (; x <= tot; x += (x & (-x)))
    		bits[x] += d;
    }
    int sum(int x) {
    	int ret = 0;
    	for (; x; x -= (x & (-x)))
    		ret += bits[x];
    	return ret;
    }
    
    void add(char *s) {
    	int len = strlen(s), x, tmp = 1, tt = 0;
    	for (int i = 0; i < len; ++i) {
    		x = s[i] - 'a';
    		if (ch[tmp][x]) tmp = ch[tmp][x];
    		else {
    			while (tmp && ch[tmp][x] == 0) tmp = fail[tmp];
    			if (ch[tmp][x]) tmp = ch[tmp][x];
    			else tmp = 1;
    		}
    		a[++tt] = tmp;
    		update(L[tmp], 1);
    	}
    	stable_sort(a + 1, a + tt + 1, cmp);
    	for (int i = 2; i <= tt; ++i)
    		update(L[LCA(a[i - 1], a[i])], -1);
    }
    
    int Sum(int x) {
    	return sum(R[x]) - sum(L[x] - 1);
    }
    
    int main() {
    	scanf("%d", &n);
    	for (int i = 1; i <= n; ++i) {
    		scanf("%s", s);
    		insert(i, s);
    	}
    	BFS();
    	dfs(1);
    	top[1] = 1; dfs2(1);
    	
    	int q, op;
    	scanf("%d", &q);
    	while (q--) {
    		scanf("%d", &op);
    		if (op == 1) {
    			scanf("%s", s);
    			add(s);
    		} else {
    			scanf("%d", &op);
    			printf("%d
    ", Sum(id[op]));
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    pytorch基础(4)-----搭建模型网络的两种方法
    Java
    Tools
    Maven
    Java
    DevOps
    Linux
    Java
    Java
    Nutch 使用总结
  • 原文地址:https://www.cnblogs.com/abclzr/p/6291849.html
Copyright © 2011-2022 走看看