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

N,M<=100000
暴力自重。。。
 
题意 : 给你一棵树,每次询问任意两点间第 K 小的元素,强调在线。
思路分析 :还是利用主席树,在树上建立主席树,从根节点到当前节点建立线段树,借助 lca, 然后比如要查询 u, v 这段区间,要先找到u, v 之间的公共祖先 lca
代码示例 :
#define ll long long
const int maxn = 1e5+5;
const int mod = 1e9+7;
const double eps = 1e-9;
const double pi = acos(-1.0);
const int inf = 0x3f3f3f3f; int n, m;
int pre[maxn], rank[maxn];
vector<int>ve[maxn];
int dep[maxn];
int grand[maxn][22];
int root[maxn];
int cnt, ss;
struct node
{
int l, r;
int sum;
}t[maxn*20]; void update(int num, int &rt, int l, int r){
t[cnt++] = t[rt];
rt = cnt-1;
t[rt].sum++; if (l == r) return;
int m = (l+r)>>1;
if (num <= m) update(num, t[rt].l, l, m);
else update(num, t[rt].r, m+1, r);
} void dfs(int x, int fa){
for(int i = 1; i <= 20; i++){
grand[x][i] = grand[grand[x][i-1]][i-1];
}
int num = lower_bound(rank+1, rank+ss, pre[x])-rank;
root[x] = root[fa];
update(num, root[x], 1, n);
for(int i = 0; i < ve[x].size(); i++){
int to = ve[x][i];
if (to == fa) continue; dep[to] = dep[x]+1;
grand[to][0] = x;
dfs(to, x);
}
} void init(){
cnt = 1;
root[0] = 0;
t[0].l = t[0].r = t[0].sum = 0;
} int getlca(int u, int v){
if (dep[u] < dep[v]) swap(u, v); // u 是在下面的 for(int i = 20; i >= 0; i--){
if (dep[grand[u][i]] >= dep[v]) u = grand[u][i];
}
if (u == v) return u; for(int i = 20; i >= 0; i--){
if (grand[u][i] != grand[v][i]){
u = grand[u][i];
v = grand[v][i];
}
}
return grand[u][0];
} int query(int t1, int t2, int t3, int t4, int k, int l, int r){
int d = t[t[t1].l].sum+t[t[t2].l].sum-t[t[t3].l].sum-t[t[t4].l].sum;
//printf("l = %d r = %d d = %d\n", l, r, d);
if (l == r) return l;
int m = (l+r)>>1;
if (k <= d) return query(t[t1].l, t[t2].l, t[t3].l, t[t4].l, k, l, m);
else return query(t[t1].r, t[t2].r, t[t3].r, t[t4].r, k-d, m+1, r);
}
int last=0; int main() {
//freopen("in.txt", "r", stdin);
//freopen("out.txt", "w", stdout);
cin >> n >> m;
for(int i = 1; i <= n; i++){
scanf("%d", &pre[i]);
rank[i] = pre[i];
}
sort(rank+1, rank+1+n);
ss = unique(rank+1, rank+1+n)-rank;
int a, b;
for(int i = 1; i < n; i++){
scanf("%d%d", &a, &b);
ve[a].push_back(b), ve[b].push_back(a);
}
dep[1] = 1;
init();
dfs(1, 0); int u, v, k;
for(int i = 1; i <= m; i++){
scanf("%d%d%d", &u, &v, &k);
u ^= last;
//printf("*** u = %d v = %d\n", u, v);
int lca = getlca(u, v);
int ans = query(root[u], root[v], root[lca], root[grand[lca][0]], k, 1, n);
last = rank[ans];
//printf("*** ans = %d\n", ans);
printf("%d\n", rank[ans]);
}
return 0;
}

树上主席树 - 查询树链上第K大的更多相关文章

  1. 主席树——树链上第k大spoj COT

    首先要求第k大就想到用主席树来处理 但是不能直接用树链剖分的dfs序来维护,因为一条链对应的dfs下标可能是断开的几段,无法用权值线段树来维护 那么久维护每个点到根节点的全值线段树,结点u的权值线段树 ...

  2. ZOJ -2112 Dynamic Rankings 主席树 待修改的区间第K大

    Dynamic Rankings 带修改的区间第K大其实就是先和静态区间第K大的操作一样.先建立一颗主席树, 然后再在树状数组的每一个节点开线段树(其实也是主席树,共用节点), 每次修改的时候都按照树 ...

  3. 利用划分树求解整数区间内第K大的值

    如何快速求出(在log2n的时间复杂度内)整数区间[x,y]中第k大的值(x<=k<=y)? 其实我刚开始想的是用快排来查找,但是其实这样是不行的,因为会破坏原序列,就算另外一个数组来存储 ...

  4. G - KiKi's K-Number(树状数组求区间第k大)

    For the k-th number, we all should be very familiar with it. Of course,to kiki it is also simple. No ...

  5. 线段树专题2-(加强版线段树-可持续化线段树)主席树 orz! ------用于解决区间第k大的问题----xdoj-1216

    poj-2104(区间第K大问题) #include <iostream> #include <algorithm> #include <cstdio> #incl ...

  6. 【POJ2104】【整体二分+树状数组】区间第k大

    Description You are working for Macrohard company in data structures department. After failing your ...

  7. 【Tyvj2133&BZOJ1146】网络管理Network(树套树,DFS序,树状数组,主席树,树上差分)

    题意:有一棵N个点的树,每个点有一个点权a[i],要求在线实现以下操作: 1:将X号点的点权修改为Y 2:查询X到Y的路径上第K大的点权 n,q<=80000 a[i]<=10^8 思路: ...

  8. 可持久化线段树(主席树)——静态区间第k大

    主席树基本操作:静态区间第k大 #include<bits/stdc++.h> using namespace std; typedef long long LL; ,MAXN=2e5+, ...

  9. 可持久化线段树(主席树)(图文并茂详解)【poj2104】【区间第k大】

    [pixiv] https://www.pixiv.net/member_illust.php?mode=medium&illust_id=63740442 向大(hei)佬(e)实力学(di ...

随机推荐

  1. [C++] 检查随机内存溢出

    C++程序的随机内存溢出是非常难处理的,windows提供了一些工具来缓解这个问题. windows debuger提供的Global Flags可以设置"enable heap tail ...

  2. Scrap简介

    原文:https://blog.csdn.net/ssw_1990/article/details/51254227 提到Python与网络爬虫,可能会想到urllib,urllib2,Beautif ...

  3. Scrapy项目注意事项

  4. 2019-8-30-C#-反射调用私有事件

    title author date CreateTime categories C# 反射调用私有事件 lindexi 2019-08-30 08:52:57 +0800 2018-09-19 20: ...

  5. P1092 电子表格

    题目描述 在流行的电子表格系统中(例如,在Excel中),使用如下计算方式来对列号进行计算. 第1列对应A,第2列对应B,--,第26列对应Z.然后使用两个大写英文字母来表示列:第27列对应AA,第2 ...

  6. Redis 命令行工具能这样用你知道了吗?

    我们天天都在使用 Redis 内置的命令行工具 redis-cli,久而久之以为它就是一个简单的交互式 Redis 数据结构手工操作程序,但是它背后强大的功能绝大多数同学可能闻所未闻.本节我们一起来挖 ...

  7. ZeroNet搭建个人网站,一些搞笑图片

    ZeroNet是一个利用比特币加密和BT技术提供不受审查的网络与通信的BT平台,ZeroNet网络功能已经得到完整的种子的支持和加密连接,保证用户通信和文件共享的安全.使用ZeroNet,你可以匿名上 ...

  8. linux flags 参数

    记住 kmalloc 原型是: #include <linux/slab.h> void *kmalloc(size_t size, int flags); 给 kmalloc 的第一个参 ...

  9. Linux 内核中的数据类型

    在我们进入更高级主题之前, 我们需要停下来快速关注一下可移植性问题. 现代版本的 Linux 内核是 高度可移植的, 它正运行在很多不同体系上. 由于 Linux 内核的多平台特性, 打算做认真使用的 ...

  10. 【elasticsearch】数据早8小时Or晚8小时,你知道为什么吗,附解决方案

    前言 这篇文章,不会解释什么是本初子午线,只想以做实验的方式来理解数据差8小时的问题.下面就先说结论,再来谈原理. 解决方案 想必大家都很清楚:中国标准时间= UTC + 8小时. 那么所有和时区有关 ...