题目描述

给定一棵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. spring:利用Spring AOP 使日志输入与方法分离

    对方法进行日志输出是一种很常见的功能.传统的做法是把输出语句写在方法体的内部,在调用该方法时,用输入语句输出信息来记录方法的执行! 1.先写一个普通类: package com.importnew; ...

  2. 【WIP】Rails devise导入与使用方法

    创建: 2017/09/07 更新: 2017/10/14 标题加上[WIP]     源代码: https://github.com/plataformatec/devise  命令行内容总结  安 ...

  3. Js:弹窗剧中

    js变量设置 var iWidth = $(window).width() * 0.9; var iHeight = $(window).height() * 0.9; - iHeight) / ; ...

  4. C - Alice, Bob and Chocolate(贪心)

    Problem description Alice and Bob like games. And now they are ready to start a new game. They have ...

  5. 多文件上传ajax jquery

    jquery的ajaxSubmit()和多文件上传 <%@ page language="java" import="java.util.*" pageE ...

  6. 查找索引/ie滤镜/动态背景/属性attr和prop

    1. 查找索引 查找当前元素在指定范围内的索引序号,示例: $('.right_newestState_con').find('em').index($(this)); 2. ie滤镜 利用ie的私有 ...

  7. VHDL之concurrent之generate

    GENERATE It is another concurrent statement (along with operators and WHEN). It is equivalent to the ...

  8. Windows 10 新功能

    一.与 Cortana 集成的便笺 借助便笺,你可捕捉并保存绝妙创意或记录重要细节.便笺现已与 Cortana 集成,让你能够设置整个设备中的提醒. (一)   先来了解一下微软小娜Cortana. ...

  9. 【sqli-labs】 less20 POST - Cookie injections - Uagent field - Error based (POST型基于错误的cookie头部注入)

    以admin admin成功登陆之后,保存并显示了cookies信息 如果不点击Delete Your Cookie!按钮,那么访问 http://localhost/sqli-labs-master ...

  10. node、Mongo项目如何前后端分离提供接口给前端

    node接口编写,vue-cli代理接口方法  通常前端使用的MocK 数据的方法,去模拟假的数据,但是如果有node Mongodb 去写数据的话就不需要在去mock 数据了,具体的方法如下. 首先 ...