【NOIP2017提高A组模拟9.14】生命之树 (dsu on tree+trie)
来源:互联网 发布:xquartz2.7.5 mac 编辑:程序博客网 时间:2024/06/05 12:00
Description:
1<=n<=
题解:
这是一道树上启发式的题目,也算是我做得树上启发式的第一题,这次比赛一下出现了两题树上启发式,都不会,让人无语。
看到xor,马上拆位,这个都是老套路了。
对于一个点u,把它和它的子树的字符串全部一次丢到一个trie里,因为已经拆了位,随便维护一下就可以求出答案。
但是我们知道这样暴力是很慢的,复杂度易得。
利用启发式可以把暴力的复杂度优化。
大概流程如下:
对于一个点x,先计算其轻儿子的答案,做完以后,全局的trie是清空的。
接着计算其重儿子的答案,注意此时重儿子的所有子树的节点的字符串是在trie里。
接着再把x的除重儿子子树外的所有节点加入trie,x也要加进trie里。
这样x的子树的答案就已经计算出来了。
如果x是其父亲节点的重儿子,保留当前的trie,否则清空trie。
我们可以分析一下复杂度:
一个点被加入trie的次数就是它到根的路径上的轻重链数的总和,有加入才有删除。
所以复杂度是:
Code:
#include<cstdio>#include<cstring>#define ll long long#define fo(i, x, y) for(int i = x; i <= y; i ++)using namespace std;const int N = 500005;char s[N], S[N];int a2[17], w;int n, x, y, a[N][17], l[N], r[N];int final[N], tot;struct edge { int to, next;}e[N * 2];int fa[N], bz[N], siz[N], son[N];int next[N][26], tt = 1, root = 1;ll ans[N], ans2[N], sm[N][2];void link(int x, int y) { e[++ tot].next = final[x], e[tot].to = y, final[x] = tot; e[++ tot].next = final[y], e[tot].to = x, final[y] = tot; }void dg(int x) { bz[x] = 1; siz[x] = 1; for(int i = final[x]; i; i = e[i].next) { int y = e[i].to; if(bz[y]) continue; fa[y] = x; dg(y); siz[x] += siz[y]; son[x] = siz[y] > siz[son[x]] ? y : son[x]; } bz[x] = 0; }ll Insert(int x) { int y = root; ll sum = 0; fo(i, l[x], r[x]) { int c = s[i] - 'a'; if(next[y][c] == 0) next[y][c] = ++ tt; y = next[y][c]; sum += sm[y][!a[x][w]] * a2[w]; sm[y][a[x][w]] ++; } return sum;}ll dfs(int x) { bz[x] = 1; ll sum = Insert(x); for(int i = final[x]; i; i = e[i].next) { int y = e[i].to; if(bz[y]) continue; sum += dfs(y); } bz[x] = 0; return sum;}void dg2(int x) { bz[x] = 1; for(int i = final[x]; i; i = e[i].next) { int y = e[i].to; if(bz[y] || y == son[x]) continue; dg2(y); } if(son[x] != 0) dg2(son[x]), ans[x] += ans[son[x]]; for(int i = final[x]; i; i = e[i].next) { int y = e[i].to; if(bz[y] || y == son[x]) continue; ans[x] += dfs(y); } ans[x] += Insert(x); if(x != son[fa[x]]) { fo(i, 1, tt) memset(next[i], 0, sizeof(next[i])), sm[i][0] = sm[i][1] = 0; tt = 1; } bz[x] = 0;}int main() { freopen("tree.in", "r", stdin); freopen("tree.out", "w", stdout); scanf("%d", &n); fo(i, 1, n) { scanf("%d", &x); fo(j, 0, 16) a[i][j] = x & 1, x /= 2; } fo(i, 1, n) { scanf("%s", S + 1); int len = strlen(S + 1); l[i] = r[i - 1] + 1; r[i] = r[i - 1] + len; fo(j, l[i], r[i]) s[j] = S[j - l[i] + 1]; } fo(i, 1, n - 1) { scanf("%d %d", &x, &y); link(x, y); } dg(1); a2[0] = 1; fo(i, 1, 16) a2[i] = a2[i - 1] * 2; for(w = 0; w <= 16; w ++) { dg2(1); fo(i, 1, n) ans2[i] += ans[i], ans[i] = 0; } fo(i, 1, n) printf("%lld\n", ans2[i]);}
阅读全文
1 0
- 【NOIP2017提高A组模拟9.14】生命之树 (dsu on tree+trie)
- jzoj5363【NOIP2017提高A组模拟9.14】生命之树 trie+启发式合并
- 【NOIP2017提高A组模拟9.14】生命之树 trie+启发式合并
- JZOJ 5406. 【NOIP2017提高A组模拟10.10】Tree
- [jzoj5406]【NOIP2017提高A组模拟10.10】Tree
- JZOJ5397. 【NOIP2017提高A组模拟10.6】Biology trie+LCA/哈希
- JZOJ5361. 【NOIP2017提高A组模拟9.14】捕老鼠
- A【NOIP2017提高组模拟12.18】
- 【JZOJ4928】【NOIP2017提高组模拟12.18】A
- 【NOIP2017提高组模拟12.18】A
- 【JZOJ4928】【NOIP2017提高组模拟12.18】A
- 【NOIP2017提高A组模拟7.7】图
- 【NOIP2017提高A组模拟7.13】abcd
- 区间【NOIP2017提高A组模拟7.10】
- 【NOIP2017提高A组模拟8.22】密码
- 【NOIP2017提高A组模拟8.23】密码
- 【NOIP2017提高A组模拟8.24】早苗
- 【NOIP2017提高A组模拟8.24】提米树
- android 多线程实现方式、并发与同步学习总结
- Codeforces Round #434 (Div.2)
- 东秦图灵杯.平方和和立方和·
- 搜狐2018校招笔试题
- 使用OpenCV训练Haar like+Adaboost分类器的常见问题
- 【NOIP2017提高A组模拟9.14】生命之树 (dsu on tree+trie)
- 1266:寻找幸运数
- tensorflow之session用法简述
- UVA 796 Critical Links(Tarjan求割边)
- 一个简单的51操作系统
- html、css常考的知识点
- 维护篇 17. 固件升级路径表 ❀ 飞塔 (Fortinet) 防火墙
- 全面理解Java内存模型
- HDU 6208 AC自动机 或 暴力?