题目描述

给定一棵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行,表示每个询问的答案。最后一个询问不输出换行符

样例输入

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

样例输出

2
8
9
105
7

提示

HINT:
N,M<=100000
 
  
  查询一个路径上第k小,就相当于查询序列上区间第k小,可以想到用主席树维护。但这道题是在树上完成的操作,所以并不能像平常主席树一样只用r时刻减掉l-1时刻的线段树查询。对于树上的路径(以x和y之间的路径为例),可以把它分成两部分:x到lca和y到lca。这样整条路径上的信息就可以通过这两条链相加得到。所以直接用x时刻线段树+y时刻线段树-lca时刻线段树-lca的父节点时刻线段树就得到路径上状态。每个时刻线段树由它的父节点时刻线段树转移过来。
最后附上代码。
#include<map>
#include<set>
#include<queue>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define mid (L+R)/2
using namespace std;
int ans;
int tot;
int cnt;
int anc;
int n,m,q;
int x,y,z;
int d[100010];
int v[100010];
int h[100010];
int l[3000010];
int r[3000010];
int to[200010];
int head[100010];
int next[200010];
int sum[3000010];
int root[100010];
int f[100010][20];
map<int,int>b;
void add(int x,int y)
{
tot++;
next[tot]=head[x];
head[x]=tot;
to[tot]=y;
}
int lca(int x,int y)
{
if(d[x]<d[y])
{
swap(x,y);
}
int dep=d[x]-d[y];
for(int i=0;i<=19;i++)
{
if((dep&(1<<i))!=0)
{
x=f[x][i];
}
}
if(x==y)
{
return x;
}
for(int i=19;i>=0;i--)
{
if(f[x][i]!=f[y][i])
{
x=f[x][i];
y=f[y][i];
}
}
return f[x][0];
}
int updata(int pre,int L,int R,int k)
{
int rt=++cnt;
l[rt]=l[pre];
r[rt]=r[pre];
sum[rt]=sum[pre]+1;
if(L==R)
{
return rt;
}
else
{
if(k<=mid)
{
l[rt]=updata(l[pre],L,mid,k);
}
else
{
r[rt]=updata(r[pre],mid+1,R,k);
}
}
return rt;
}
int query(int x,int y,int anc,int fa,int L,int R,int k)
{
if(L==R)
{
return b[L];
}
int num=sum[l[x]]+sum[l[y]]-sum[l[anc]]-sum[l[fa]];
if(num>=k)
{
return query(l[x],l[y],l[anc],l[fa],L,mid,k);
}
else
{
return query(r[x],r[y],r[anc],r[fa],mid+1,R,k-num);
}
}
void dfs(int x,int fa)
{
d[x]=d[fa]+1;
int k=lower_bound(h+1,h+1+m,v[x])-h;
b[k]=v[x];
root[x]=updata(root[fa],1,n,k);
for(int i=1;i<=19;i++)
{
f[x][i]=f[f[x][i-1]][i-1];
}
for(int i=head[x];i;i=next[i])
{
if(to[i]!=fa)
{
f[to[i]][0]=x;
dfs(to[i],x);
}
}
}
int main()
{
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++)
{
scanf("%d",&v[i]);
h[i]=v[i];
}
sort(h+1,h+1+n);
m=unique(h+1,h+1+n)-h-1;
for(int i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
dfs(1,0);
for(int i=1;i<=q;i++)
{
scanf("%d%d%d",&x,&y,&z);
x=x^ans;
anc=lca(x,y);
ans=query(root[x],root[y],root[anc],root[f[anc][0]],1,n,z);
printf("%d\n",ans);
}
}

BZOJ2588Count on a tree——LCA+主席树的更多相关文章

  1. [BZOJ2588]Count on a tree(LCA+主席树)

    题面 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权.其中lastans是上一个询问的答案,初始为0,即第一个询问 ...

  2. 【bzoj2588/P2633】count on a tree —— LCA + 主席树

    (以下是luogu题面) 题目描述 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权.其中lastans是上一个询问 ...

  3. BZOJ 2588: Spoj 10628. Count on a tree( LCA + 主席树 )

    Orz..跑得还挺快的#10 自从会树链剖分后LCA就没写过倍增了... 这道题用可持久化线段树..点x的线段树表示ROOT到x的这条路径上的权值线段树 ----------------------- ...

  4. 【BZOJ2588】Count On a Tree(主席树)

    [BZOJ2588]Count On a Tree(主席树) 题面 题目描述 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第 ...

  5. LCA+主席树 (求树上路径点权第k大)

      SPOJ 10628. Count on a tree (树上第k大,LCA+主席树) 10628. Count on a tree Problem code: COT You are given ...

  6. Count on a tree 树上主席树

    Count on a tree 树上主席树 给\(n\)个树,每个点有点权,每次询问\(u,v\)路径上第\(k\)小点权,强制在线 求解区间静态第\(k\)小即用主席树. 树上主席树类似于区间上主席 ...

  7. hdu 5274 Dylans loves tree(LCA + 线段树)

    Dylans loves tree Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Othe ...

  8. BZOJ_1803_Spoj1487 Query on a tree III_主席树+dfs序

    BZOJ_1803_Spoj1487 Query on a tree III_主席树 Description You are given a node-labeled rooted tree with ...

  9. 【bzoj3123】[Sdoi2013]森林 倍增LCA+主席树+启发式合并

    题目描述 输入 第一行包含一个正整数testcase,表示当前测试数据的测试点编号.保证1≤testcase≤20. 第二行包含三个整数N,M,T,分别表示节点数.初始边数.操作数.第三行包含N个非负 ...

随机推荐

  1. QT显示url图片

    QT 显示网络图片我目前的办法就是先下载下来 然后显示  如果有好的办法请相互交流一下 需要调用的头文件 #include <QNetworkAccessManager> #include ...

  2. JQuery将form表单值转换成json字符串函数

    由于后台接口限定,必须要将表单内容转换成json字符串提交,因此写了一个将form表单值转成json字符串的函数.     前提:页面引入了JQuery          下面直接上代码 一.代码 / ...

  3. WPF模拟探照灯文字

    原文:WPF模拟探照灯文字 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/yangyisen0713/article/details/1835936 ...

  4. Ionic Android项目Splash设置

    ionic项目中,在splashscreen消失后会出现零点几秒的白屏,再出现app页面. 1. 安装Cordova splash screen插件 ionic plugin add org.apac ...

  5. [转]Office导入导出组件权限配置汇总

    原文地址:Office导入导出组件权限配置汇总 具体配置方法如下:  1:在服务器上安装office的Excel软件.  2:在"开始"->"运行"中输入 ...

  6. Luogu P1546 最短网络 Agri-Net

    其实这道题根本没必要写,但为了测试vector+堆优化的Prim试一发. 再次觉得Prim和Dijkstra很像,堆优化版本也差不多. 和Dijkstra一样,Prim也是在之前的dis点中选取一个最 ...

  7. 面试4——java进程和线程相关知识

    1.线程和进程的概念.并行和并发的概念

  8. 自己动手写把”锁”---LockSupport深入浅出

    本篇是<自己动手写把"锁">系列技术铺垫的最后一个知识点.本篇主要讲解LockSupport工具类,它用来实现线程的挂起和唤醒. LockSupport是Java6引入 ...

  9. Sql_join left right

    1.内连接inner join 只返回两张表中所有满足连接条件的行,即使用比较运算符根据每个表中共有的列的值匹配两个表中的行.(inner关键字是可省略的) ①传统的连接写法: 在FROM子句中列出所 ...

  10. Mysql读写分离方案-MySQL Proxy环境部署记录

    Mysql的读写分离可以使用MySQL Proxy和Amoeba实现,其实也可以使用MySQL-MMM实现读写分离的自动切换.MySQL Proxy有一项强大功能是实现"读写分离" ...