您的位置:首页 > 编程语言 > C语言/C++

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 5

105 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

2

8

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++ LCA 主席树