题目描述

给定一棵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

说明

HINT:

N,M<=100000

暴力自重。。。

来源:bzoj2588 Spoj10628.

本题数据为洛谷自造数据,使用CYaRon耗时5分钟完成数据制作。

思路:主席树+LCA

以点的dfs序为下标,以点权为区间建立主席树

以前做过的主席树在序列上,所以是以前一个节点的线段树为基准建立的

这里在树上,所以可以考虑以根为基准建立线段树

u,v间增加的点数=cnt[u]+cnt[v]-cnt[LCA(u,v)]-cnt[father[LCA(u,v)]]

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define MAXN 100001
using namespace std;
int n,m,tot,cnt,num,lastans;
int a[MAXN],ha[MAXN],root[MAXN];
int to[MAXN*],net[MAXN*],head[MAXN*];
int top[MAXN],dad[MAXN],deep[MAXN],size[MAXN];
struct nond{
int l,r,cnt;
}tree[MAXN*];
void add(int u,int v){
to[++tot]=v;net[tot]=head[u];head[u]=tot;
to[++tot]=u;net[tot]=head[v];head[v]=tot;
}
void insert(int pre,int &now,int l,int r,int k){
tree[now=++num].cnt=tree[pre].cnt+;
if(l==r) return ;
int mid=(l+r)/;
if(k<=mid){
tree[now].r=tree[pre].r;
insert(tree[pre].l,tree[now].l,l,mid,k);
}
else{
tree[now].l=tree[pre].l;
insert(tree[pre].r,tree[now].r,mid+,r,k);
}
}
int query(int x,int y,int LCA,int fa_LCA,int l,int r,int k){
if(l==r) return a[l];
int mid=(l+r)/;
int tmp=tree[tree[x].l].cnt+tree[tree[y].l].cnt-tree[tree[LCA].l].cnt-tree[tree[fa_LCA].l].cnt;
if(k<=tmp) query(tree[x].l,tree[y].l,tree[LCA].l,tree[fa_LCA].l,l,mid,k);
else query(tree[x].r,tree[y].r,tree[LCA].r,tree[fa_LCA].r,mid+,r,k-tmp);
}
void dfs(int now){
size[now]=;
insert(root[dad[now]],root[now],,cnt,ha[now]);
deep[now]=deep[dad[now]]+;
for(int i=head[now];i;i=net[i])
if(dad[now]!=to[i]){
dad[to[i]]=now;
dfs(to[i]);
size[now]+=size[to[i]];
}
}
void dfs1(int x){
int t=;
if(top[x]==) top[x]=x;
for(int i=head[x];i;i=net[i])
if(dad[x]!=to[i]&&size[to[i]]>size[t])
t=to[i];
if(t){
top[t]=top[x];
dfs1(t);
}
for(int i=head[x];i;i=net[i])
if(dad[x]!=to[i]&&t!=to[i])
dfs1(to[i]);
}
int lca(int x,int y){
for(;top[x]!=top[y];){
if(deep[top[x]]<deep[top[y]])
swap(x,y);
x=dad[top[x]];
}
if(deep[x]>deep[y])
swap(x,y);
return x;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++){
scanf("%d",&a[i]);
ha[i]=a[i];
}
for(int i=;i<n;i++){
int u,v;
scanf("%d%d",&u,&v);
add(u,v);
}
sort(a+,a++n);
cnt=unique(a+,a++n)-(a+);
for(int i=;i<=n;i++)
ha[i]=lower_bound(a+,a++cnt,ha[i])-a;
dfs();
dfs1();
for(int i=;i<=m;i++){
int u,v,k;
scanf("%d%d%d",&u,&v,&k);
u^=lastans;
int LCA=lca(u,v);
lastans=query(root[u],root[v],root[LCA],root[dad[LCA]],,cnt,k);
if(i!=m) cout<<lastans<<endl;
else cout<<lastans;
}
}

洛谷 P2633 Count on a tree的更多相关文章

  1. 洛谷P2633 Count on a tree(主席树上树)

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

  2. 洛谷P2633 Count on a tree(主席树,倍增LCA)

    洛谷题目传送门 题目大意 就是给你一棵树,每个点都有点权,每次任意询问两点间路径上点权第k小的值(强制在线). 思路分析 第k小......又是主席树了.但这次变成树了,无法直接维护前缀和. 又是树上 ...

  3. 洛谷P2633 Count on a tree(主席树,倍增LCA,树上差分)

    洛谷题目传送门 题目大意 就是给你一棵树,每个点都有点权,每次任意询问两点间路径上点权第k小的值(强制在线). 思路分析 第k小......又是主席树了.但这次变成树了,无法直接维护前缀和. 又是树上 ...

  4. 洛谷P2633 Count on a tree

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

  5. 洛谷 P2633 Count on a tree 主席树

    在一棵树上,我们要求点 $(u,v)$ 之间路径的第$k$大数. 对于点 $i$  ,建立 $i$  到根节点的一棵前缀主席树. 简单容斥后不难得出结果为$sumv[u]+sumv[v]−sumv[l ...

  6. 洛谷 P2633 Count on a tree 题解

    题面 对于每个点建立一颗主席树: 然后按照树上差分的思想统计主席树的前缀和: lca+主席树+前向星存表就可以了: #include <bits/stdc++.h> #define inc ...

  7. ☆ [洛谷P2633] Count on a tree 「树上主席树」

    题目类型:主席树+\(LCA\) 传送门:>Here< 题意:给出一棵树.每个节点有点权.问某一条路径上排名第\(K\)小的点权是多少 解题思路 类似区间第\(K\)小,但放在了树上. 考 ...

  8. 洛谷P2633 Count on a tree 主席树

    传送门:主席树 解题报告: 传送门! umm这题我还麻油开始做 所以 先瞎扯一波我的想法,如果错了我就当反面教材解释这种典型错误,对了我就不管了QwQ 就直接dfs,在dfs的过程中建树 然后就直接查 ...

  9. 洛谷 P6177 - Count on a tree II/【模板】树分块(树分块)

    洛谷题面传送门 好家伙,在做这道题之前我甚至不知道有个东西叫树分块 树分块,说白了就是像对序列分块一样设一个阈值 \(B\),然后在树上随机撒 \(\dfrac{n}{B}\) 个关键点,满足任意一个 ...

随机推荐

  1. PCB MS SQL 将字符串分割,并指定索引返回字符串(标量函数)

    Create FUNCTION [dbo].[SplitIndex] ( @str AS VARCHAR(max), @Index AS INT, ) = '/' ) ) AS BEGIN ) --待 ...

  2. thinkphp方便分页的page方法

    page方法也是模型的连贯操作方法之一,是完全为分页查询而诞生的一个人性化操作方法. 用法 我们在前面已经了解了关于limit方法用于分页查询的情况,而page方法则是更人性化的进行分页查询的方法,例 ...

  3. codeforces——思路与规律

    codeforces 804B     http://codeforces.com/problemset/problem/804/B /* 题意:给定一个只含ab的序列,每次操作可将ab变为bba 问 ...

  4. Coursera公开课-Machine_learing:编程作业5

    Regularized Linear Regression and Bias/Variance 大多数时候,我们使用机器学习方法得到的结果都不是特别理想,常见 欠拟合 和 过拟合 问题.通过一些变量画 ...

  5. Android高亮TextView

    HighlightTextView Android文本高亮控件,基于View实现. 特点 文本高亮 单词自动换行 高亮词组保持在同一行显示 截图 Demo Java: public class Mai ...

  6. JWPL工具处理维基百科wikipedia数据用于NLP

    JWPL处理维基百科数据用于NLP 处理zhwiki JWPL是一个Wikipedia处理工具,主要功能是将Wikipedia dump的文件经过处理.优化导入mysql数据库,用于NLP过程.以下以 ...

  7. 【python】os.getcwd和getcwdu

    print os.getcwd(), type(os.getcwd()) print os.getcwdu(), type(os.getcwdu()) 结果如下: C:\Users\Administr ...

  8. svn命令行批量删除和批量添加

    svn命令行批量删除和批量添加 如果使用svn的命令行,例如在linux下的终端中使用,svn的添加命令是svn add,删除命令是svn del,但是缺乏批量的操作,如果我在资源管理器中,手动添加了 ...

  9. 我的web前端自学之路-心得篇:我为什么要学习web前端?

    时光如流水,转眼间,自己已经是大三的学长了,看着一个个学弟学妹,心中有种莫名的感觉,很怀念大学的前两年时光,但也很憧憬着自己的未来,自己将要去经历很多从未经历的事.我是我们学校信科院的一名学生,在编程 ...

  10. <转>c++引用与指针的区别(着重理解)

     ★ 相同点: 1. 都是地址的概念: 指针指向一块内存,它的内容是所指内存的地址:引用是某块内存的别名.  ★ 区别: 1. 指针是一个实体,而引用仅是个别名: 2. 引用使用时无需解引用(*),指 ...