洛谷传送门
题目描述
给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权。其中lastans是上一个询问的答案,初始为0,即第一个询问的u是明文。
输入输出格式
输入格式:
第一行两个整数N,M。
第二行有N个整数,其中第i个整数表示点i的权值。
后面N-1行每行两个整数(x,y),表示点x到点y有一条边。
最后M行每行两个整数(u,v,k),表示一组询问。
输出格式:
M行,表示每个询问的答案。
输入输出样例
输入样例#1:
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
输出样例#1:
2
8
9
105
7
解题分析
经典的链上静态第K大模板(强制在线)。
回想我们平时是如何处理的第K大问题:要么排序
O(1)
O
(
1
)
得到答案, 要么使用主席树查询。
在树上排序显然是不可能以一个较为优秀的的复杂度得到答案的(用STL里的kth_element函数也只能做到每次
O(n)
O
(
n
)
), 那么我们只好采用主席树了。
那么我们该如何建树呢?考虑到主席树具有可加减的性质, 我们可以在离散化后对每个节点建出其到根节点的所有点点权的主席树, 再求出两个查询端点的LCA, 去掉重复的部分就可以得到链上的所有值。
代码如下:
#include <cstdio>
#include <cstring>
#include <cctype>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#define R register
#define IN inline
#define gc getchar()
#define W while
#define ls tree[now].son[0]
#define rs tree[now].son[1]
#define MXX 20000500
#define MX 200005
template <class T>
IN void in (T &x)
{
x = 0; R char c = gc;
W (!isdigit(c)) c = gc;
W (isdigit(c))
{x = (x << 1) + (x << 3) + c - 48, c = gc;}
}
namespace President_Tree
{
int dep[MX], top[MX], head[MXX], dfn[MX], ref[MX], fat[MX], son[MX], rk[MX];
int siz[MX], cnt, tot, arr, ct, root[MXX];
long long dat[MX], val[MX];
int dot, q, lastans;
struct Node
{
int son[2], val, siz, sum;
}tree[MX << 5];
struct Edge
{
int to, nex;
}edge[MX];
IN void addedge(const int &from, const int &to)
{
edge[++cnt] = (Edge){to, head[from]};
head[from] = cnt;
}
void DFS1(const int &now)
{
dfn[now] = ++tot;
ref[tot] = now;
siz[now] = 1;
for (int i = head[now]; i; i = edge[i].nex)
{
if(dfn[edge[i].to]) continue;
dep[edge[i].to] = dep[now] + 1;
fat[edge[i].to] = now;
DFS1(edge[i].to);
siz[now] += siz[edge[i].to];
if(siz[son[now]] < siz[edge[i].to]) son[now] = edge[i].to;
}
}
void DFS2(const int &now, const int &grand)
{
top[now] = grand;
if(!son[now]) return;
DFS2(son[now], grand);
for (int i = head[now]; i; i = edge[i].nex)
{
if(edge[i].to == son[now] || edge[i].to == fat[now]) continue;
DFS2(edge[i].to, edge[i].to);
}
}
IN int LCA (R int x, R int y)
{
W (top[x] != top[y])
{
if(dep[top[x]] < dep[top[y]]) std::swap(x, y);
x = fat[top[x]];
}
return dep[x] > dep[y] ? y : x;
}
void modify(int &now, const int &lef, const int &rig, const int &pre, const int &tar)
{
now = ++arr;
tree[now].sum = tree[pre].sum + 1;
if(lef == rig) return;
ls = tree[pre].son[0], rs = tree[pre].son[1];
int mid = (lef + rig) >> 1;
if(tar <= mid) modify(ls, lef, mid, tree[pre].son[0], tar);
else modify(rs, mid + 1, rig, tree[pre].son[1], tar);
}
int query(int lef, int rig, int kth)
{
int lca = LCA(lef, rig);
int lb = root[dfn[lef]], rb = root[dfn[rig]], ub = root[dfn[lca]], up = root[dfn[fat[lca]]], mid, cntt;
lef = 1, rig = ct;
W (lef < rig)
{
mid = (lef + rig) >> 1;
cntt = tree[tree[lb].son[0]].sum + tree[tree[rb].son[0]].sum - tree[tree[ub].son[0]].sum - tree[tree[up].son[0]].sum;
if(cntt >= kth) rig = mid, lb = tree[lb].son[0], rb = tree[rb].son[0], ub = tree[ub].son[0], up = tree[up].son[0];
else kth -= cntt, lef = mid + 1, lb = tree[lb].son[1], rb = tree[rb].son[1], ub = tree[ub].son[1], up = tree[up].son[1];
}
return val[lef];
}
}
using namespace President_Tree;
int main(void)
{
int a, b, c;
in(dot), in(q);
for (R int i = 1; i <= dot; ++i) in(dat[i]);
for (R int i = 1; i < dot; ++i)
in(a), in(b), addedge(a, b), addedge(b, a);
DFS1(1);
DFS2(1, 1);
for (R int i = 1; i <= dot; ++i) val[i] = dat[i];
std::sort(val + 1, val + 1 + dot);
ct = std::unique(val + 1, val + 1 + dot) - val - 1;
for (R int i = 1; i <= dot; ++i) rk[i] = std::lower_bound(val + 1, val + 1 + ct, dat[i]) - val;
for (R int i = 1; i <= dot; ++i)
{
a = ref[i];
modify(root[i], 1, ct, root[dfn[fat[a]]], rk[a]);
}
W (q--)
{
in(a), in(b), in(c);
a ^= lastans;
lastans = query(a, b, c);
printf("%d\n", lastans);
}
}