BZOJ 2588 Count On a Tree 【LCA】【主席树】
2016-01-16 09:18
441 查看
http://www.lydsy.com/JudgeOnline/problem.php?id=2588
Description
给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权。其中lastans是上一个询问的答案,初始为0,即第一个询问的u是明文。
Input
第一行两个整数N,M。第二行有N个整数,其中第i个整数表示点i的权值。
后面N-1行每行两个整数(x,y),表示点x到点y有一条边。
最后M行每行两个整数(u,v,k),表示一组询问。
Output
M行,表示每个询问的答案。
Sample Input
8 5105 2 9 3 8 5 7 7
1 2
1 3
1 4
3 5
3 6
3 7
4 8
2 5 1
0 5 2
10 5 3
11 5 4
110 8 2
Sample Output
28
9
105
7
HINT
HINT:N,M<=100000
暴力自重。。。
求第K大的值,经典问题,考虑主席树。
怎么把树上的结构转化为线性的结构呢?
我们把从根节点到u和v的路径加起来,减掉根到他们lca的路径再减掉根到lca父节点的路径,就能得到u,v之间的路径了!
有了这个,我们可以在这棵树的每一个节点上都建一颗线段树,保存的是根节点到这个节点所有点权值的线段树(需要先进行离散化)。
然后我们就可以得到u到v的路径的一颗线段树(pi为i节点上的线段树):p[u]+p[v]-p[lca]-p[fa[lca]]。
然后在这颗线段树上跑Kth-Number就可以了~
速度3200MS左右
/************************************************************** Problem: 2588 User: MagHSK Language: C++ Result: Accepted Time:3252 ms Memory:35700 kb ****************************************************************/ #include <cstdio> #include <algorithm> const int maxn = 100005; int getint() { int r = 0, k = 1; char c; for (c = getchar(); c < '0' || c > '9'; c = getchar() ) if (c == '-') k = -1; for (; '0' <= c && c <= '9'; c = getchar() ) r = r * 10 - '0' + c; return r * k; } struct edge_type { int v, next; } edge[maxn*2]; int cnte = 0; int root[maxn]; int a[maxn], w[maxn], b[maxn]; int h[maxn]; int n, m; struct node_type { int ls, rs, siz; } node[maxn * 20]; int cntn = 0; void modify(int &x, int l, int r, int key) { node[++cntn] = node[x]; x = cntn; ++node[x].siz; if (l == r) return; int mid = (l + r) >> 1; if (key <= mid) modify(node[x].ls, l, mid, key); else modify(node[x].rs, mid + 1, r, key); } void build(int now, int father) { root[now] = root[father]; modify(root[now], 1, n, w[now]); for (int i = h[now]; i; i = edge[i].next) if (edge[i].v != father) build(edge[i].v, now); } bool cmp(int x, int y) { return a[x] < a[y]; } void ins(int u, int v) { edge[++cnte].v = v; edge[cnte].next = h[u]; h[u] = cnte; } int query(int u, int v, int uvlca, int fuvlca, int l, int r, int k) { int mid, tmp; while(l < r) { mid=(l+r)>>1; tmp=node[node[u].ls].siz + node[node[v].ls].siz - node[node[uvlca].ls].siz - node[node[fuvlca].ls].siz; if (k <= tmp) { r = mid; u = node[u].ls; v = node[v].ls; uvlca = node[uvlca].ls; fuvlca = node[fuvlca].ls; } else { k -= tmp; l = mid + 1; u = node[u].rs; v = node[v].rs; uvlca = node[uvlca].rs; fuvlca = node[fuvlca].rs; } } return l; } int dep[maxn], top[maxn], tid[maxn], siz[maxn], son[maxn], fat[maxn], dfs_clock = 0; void dfs1(int now, int father, int depth) { dep[now] = depth; fat[now] = father; siz[now] = 1; son[now] = 0; for (int i = h[now]; i; i = edge[i].next) if (edge[i].v != father) { dfs1(edge[i].v, now, depth + 1); siz[now] += siz[edge[i].v]; if (siz[edge[i].v] > siz[son[now]]) son[now] = edge[i].v; } } void dfs2(int now, int father, int tp) { top[now] = tp; if (son[now]) { dfs2(son[now], now, tp); for (int i = h[now]; i; i = edge[i].next) if (edge[i].v != father && edge[i].v != son[now]) dfs2(edge[i].v, now, edge[i].v); } } int lca(int u, int v) { while (top[u] != top[v]) { if (dep[top[u]] < dep[top[v]]) v = fat[top[v]]; else u = fat[top[u]]; } if (dep[u] < dep[v]) return u; else return v; } int ask(int u, int v, int k) { int x = lca(u, v); int pos = query(root[u], root[v], root[x], root[fat[x]], 1, n, k); return a[b[pos]]; } int main() { n = getint(); m = getint(); for (int i = 1; i <= n; ++i) { a[i] = getint(); b[i]=i; } std::sort(b+1, b+n+1, cmp); for (int i = 1; i <= n; ++i) w[b[i]] = i; int u, v, k; for (int i = 1; i < n; ++i) { u = getint(); v = getint(); ins(u,v); ins(v,u); } build(1, 0); dfs1(1, 0, 1); dfs2(1, 0, 1); int lastans = 0; u = getint(); v = getint(); k = getint(); u ^= lastans; lastans = ask(u, v, k); printf("%d", lastans); for (int i = 1; i < m; ++i) { u = getint(); v = getint(); k = getint(); u ^= lastans; lastans = ask(u, v, k); printf("\n%d", lastans); } return 0; }
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- 关于指针的一些事情
- c++ primer 第五版 笔记前言
- share_ptr的几个注意点
- Lua中调用C++函数示例
- Lua教程(一):在C++中嵌入Lua脚本
- Lua教程(二):C++和Lua相互传递数据示例
- C++联合体转换成C#结构的实现方法
- C++高级程序员成长之路
- C++编写简单的打靶游戏
- C++ 自定义控件的移植问题
- C++变位词问题分析
- C/C++数据对齐详细解析
- C++基于栈实现铁轨问题
- C++中引用的使用总结
- 使用Lua来扩展C++程序的方法
- C++中调用Lua函数实例
- Lua和C++的通信流程代码实例
- C与C++之间相互调用实例方法讲解
- 解析C++中派生的概念以及派生类成员的访问属性