HDU 4757 Tree (倍增算法求LCA + 可持久化Trie树)
来源:互联网 发布:数码宝贝进化图鉴软件 编辑:程序博客网 时间:2024/06/05 05:19
题目大意:
就是现在给出一棵树, 结点个数不超过10W, 每个节点上有一个不超过2^16的非负整数, 然后10W次询问, 每次询问两个节点的路径上的所有数中异或上给出的数的最大值
大致思路:
刚开始做这个题想的是树链剖分之后用线段树套Trie树来做...结果悲剧地MLE了...
另外那样做得话复杂度其实是比较大的...每次询问都是16*(logn)*logn级别的..
后来发现是个可持久化Trie树...
表示第一次写可持久化Trie树, 感觉和主席树很像, 都是多个版本的Trie的集合体, 然后由要访问的版本的不同而从不同的根节点出发来访问
对于给出的树按照父亲和儿子的关系来建立可持久化Trie树
每次访问的时候访问到的Trie树版本是考虑了从当前结点到父亲结点的路径上的所有点的一颗Trie树, 那么对于每次的路径(u, v)的查询, 就是u开始的Trie与v开始的Trie的查询减去他们的LCA的查询, 然后利用贪心的思想求出可能的最大值即可
代码如下:
Result : Accepted Memory : 41812 KB Time : 1528 ms
/* * Author: Gatevin * Created Time: 2015/10/2 15:20:38 * File Name: Sakura_Chiyo.cpp */#include<iostream>#include<sstream>#include<fstream>#include<vector>#include<list>#include<deque>#include<queue>#include<stack>#include<map>#include<set>#include<bitset>#include<algorithm>#include<cstdio>#include<cstdlib>#include<cstring>#include<cctype>#include<cmath>#include<ctime>#include<iomanip>using namespace std;const double eps(1e-8);typedef long long lint;#define maxn 100010struct Edge{ int u, v, nex; Edge(int _u, int _v, int _nex) { u = _u, v = _v, nex = _nex; } Edge(){}};Edge edge[maxn << 1];int head[maxn];int tot;void add_Edge(int u, int v){ edge[++tot] = Edge(u, v, head[u]); head[u] = tot;}int w[maxn];int father[maxn][20];int dep[maxn];int n, m;/* * 可持久化Trie树 */struct Trie{#define maxnode 2800100 int next[maxnode][2]; int L; int root[maxn]; int sz[maxnode]; void init() { L = 0; memset(root, 0, sizeof(root)); memset(sz, 0, sizeof(sz)); } int newnode() { next[L][0] = next[L][1] = -1; L++; return L - 1; } /* * 一个以root[x]开始的Trie树是树上x向上到链的数组成的Trie树 * 然后树上每个节点都用sz[u][v]表示以u向上到根的值组成的Trie树中结点v代表的出现次数 */ void insert(int x, int fa, int value)//x的父亲节点是y { x = root[x]; int y = root[fa]; for(int i = 15; i >= 0; i--) { int nex = 0; if(value & (1 << i)) nex = 1; if(next[x][nex] == -1) { int id = newnode(); next[x][nex] = id; next[x][nex^1] = next[y][nex^1];//合并 sz[next[x][nex]] = sz[next[y][nex]]; } x = next[x][nex], y = next[y][nex]; ++sz[x]; } } int query(int x, int y, int z, int value)//z是x和y的lca { int ret = 0, ano = w[z]; x = root[x], y = root[y], z = root[z]; for(int i = 15; i >= 0; i--) { int nex = 0; if(value & (1 << i)) nex = 1; if(sz[next[x][nex ^ 1]] + sz[next[y][nex ^ 1]] - 2*sz[next[z][nex ^ 1]] > 0)//说明在[x, y]的链上有数提供这样的路走 { x = next[x][nex ^ 1], y = next[y][nex ^ 1], z = next[z][nex ^ 1]; ret += (1 << i); } else { x = next[x][nex], y = next[y][nex], z = next[z][nex]; } } return max(ret, ano ^ value); }};Trie trie;void dfs(int now){ trie.root[now] = trie.newnode(); trie.insert(now, father[now][0], w[now]);//按照树的列的顺序插入 for(int i = head[now]; i + 1; i = edge[i].nex) { if(edge[i].v == father[now][0]) continue; father[edge[i].v][0] = now; dep[edge[i].v] = dep[now] + 1; dfs(edge[i].v); } return;}int swim(int x, int H){ for(int i = 0; H > 0; i++) { if(H & 1) x = father[x][i]; H >>= 1; } return x;}int lca(int x, int y){ int i; if(dep[x] < dep[y]) swap(x, y); int k = dep[x] - dep[y]; x = swim(x, k); if(x == y) return x; while(1) { for(i = 0; father[x][i] != father[y][i]; i++); if(i == 0) return father[x][0]; x = father[x][i - 1]; y = father[y][i - 1]; } return -1;}void answer(int x, int y, int z){ printf("%d\n", trie.query(x, y, lca(x, y), z));}bool get(int& x){ x = 0; char c; bool ined = 0; while(!ined) { c = getchar(); if(c == EOF) break; while(c >= '0' && c <= '9') { ined = 1; x = (x << 3) + (x << 1) + c - '0'; c = getchar(); } } return ined;}int main(){ while(get(n)) { get(m); memset(head, -1, sizeof(head)); tot = 0; for(int i = 1; i <= n; i++) get(w[i]); int u, v; for(int i = 1; i < n; i++) { get(u); get(v); add_Edge(u, v); add_Edge(v, u); } trie.init(); memset(father, 0, sizeof(father)); dep[1] = 1; father[1][0] = -1; dfs(1); for(int j = 1; (1 << j) <= n; j++) for(int i = 1; i <= n; i++) if(father[i][j - 1] != -1) father[i][j] = father[father[i][j - 1]][j - 1];//准备好求lca while(m--) { int x, y, z; scanf("%d %d %d", &x, &y, &z); answer(x, y, z); } } return 0;}
0 0
- HDU 4757 Tree (倍增算法求LCA + 可持久化Trie树)
- HDU 4757 Tree 可持久化trie+lca
- hdu 4757 Tree(可持久化Trie)
- [HDU4757][可持久化Trie][LCA]Tree[好题]
- 2588: Spoj 10628. Count on a tree[可持久化线段树+倍增lca]
- HDU 4757 可持久化trie树
- HDU-5801 可持久化Trie树
- HDU 4757 可持久化字典树(Trie)
- HDU 6191 Query on A Tree 可持久化trie + dfs建树 || 启发式合并trie
- BZOJ 3123 SDOI2013 森林 可持久化线段树+倍增LCA+启发式合并
- 在线倍增算法求LCA
- hdu 4757 Tree(可持久化字典树)
- hdu-4757-Tree-树链剖分+可持久化字典树
- Hdu-4757 Tree(可持久化字典树)
- hdu 4757 Tree(可持久化字典树)
- hdu 6191 可持久化trie||线段树套trie||trie启发式合并
- HDU 6191 Query on A Tree (dfs序+可持久化01Trie)
- 可持久化trie
- iOS多线程中GCD的使用
- java提高篇(一)-----理解java的三大特性之封装
- 51nod 1183 编辑距离
- [转载] 为什么全球最好的大学大半在美国?看看美国的孩子是怎么念书的
- 八大排序算法
- HDU 4757 Tree (倍增算法求LCA + 可持久化Trie树)
- java单例模式(Singleton)
- php中的绘图技术
- MapReduce编程
- java 强制性异常与非强制性异常
- OPENCV 3.3+PYTHON 2.7 配置
- TCP 窗口机制
- UI 实现多线程方式之四 GCD之自定义并行队列
- Spring Batch MultiResourceItemReader example(八)