P2633 Count on a tree(主席树)
题目描述
给定一棵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.
题解
一道比较涨见识的题目吧。
在这里我们要统计一条路径上的Kth值,考虑把路径转化为一条序列。怎么转换?
我们可以让新增的那个点在原有的fa节点上再建树。这样我们就可以利用树上差分了。
但是我们会发现,x,y两个节点减去两次它们共同的LCA时,LCA的值就没有算在里面了,这个时候我们就不要减去两次LCA应该减去一次LCA,减去一次fa[LCA]。这里的点都是指在主席树相对应的状态。
代码
#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
const int N=100001;
int top[N],size[N],fa[N],dep[N],son[N];
int ch[N],n,m,q,b[N],tr[N<<5],sum[N<<5],tot,l[N<<5],r[N<<5];
int num,head[N],cnt;
struct node{
int to,next;
}e[N<<1];
int read()
{
int x=0,w=1;char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x*w;
}
void add(int from,int to){
num++;
e[num].to=to;
e[num].next=head[from];
head[from]=num;
}
void dfs1(int x){
size[x]=1;
for(int i=head[x];i;i=e[i].next){
int v=e[i].to;
if(!dep[v]){
dep[v]=dep[x]+1;fa[v]=x;
dfs1(v);size[x]+=size[v];
if(son[son[x]]<size[v])son[x]=v;
}
}
}
void dfs2(int x,int tp){
top[x]=tp;if(son[x])dfs2(son[x],tp);
for(int i=head[x];i;i=e[i].next){
int v=e[i].to;if(v!=fa[x]&&v!=son[x])dfs2(v,v);
}
}
int cal(int x,int y){
int fx=top[x],fy=top[y];
while(fx!=fy){
if(dep[fx]<dep[fy])swap(fx,fy),swap(x,y);
x=fa[fx],fx=top[x];
}
if(dep[x]>=dep[y])return y;return x;
}
int build(int left,int right){
int mid=(left+right)>>1;
int root=++cnt;
sum[root]=0;
if(left<right){
l[root]=build(left,mid);
r[root]=build(mid+1,right);
}
return root;
}
int update(int pre,int left,int right,int v){
int mid=(left+right)>>1;
int root=++cnt;
l[root]=l[pre];r[root]=r[pre];sum[root]=sum[pre]+1;
if(left<right){
if(v<=mid)l[root]=update(l[pre],left,mid,v);
else r[root]=update(r[pre],mid+1,right,v);
}
return root;
}
int query(int u1,int u2,int v1,int v2,int left,int right,int k){
int mid=(left+right)>>1;
int x=sum[l[u1]]+sum[l[u2]]-sum[l[v1]]-sum[l[v2]];
if(left>=right)return left;
if(x>=k)return query(l[u1],l[u2],l[v1],l[v2],left,mid,k);
else return query(r[u1],r[u2],r[v1],r[v2],mid+1,right,k-x);
}
void dfs(int x){
int t=lower_bound(b+1,b+m+1,ch[x])-b;
tr[x]=update(tr[fa[x]],1,m,t);
for(int i=head[x];i;i=e[i].next){
int v=e[i].to;
if(v!=fa[x])dfs(v);
}
}
int main()
{
n=read();q=read();
for(int i=1;i<=n;i++)
{
b[i]=ch[i]=read();
}
sort(b+1,b+n+1);
m=unique(b+1,b+n+1)-b-1;
for(int i=1;i<n;i++)
{
int x=read(),y=read();
add(x,y);add(y,x);
}
fa[1]=0;dep[1]=1;
dfs1(1);dfs2(1,0);
tr[0]=build(1,m);
dfs(1);
int last=0;
while(q--)
{
int l=read(),r=read(),k=read();
int lca=cal(l^last,r);
int ff=fa[lca];
printf("%d\n",last=b[query(tr[l^last],tr[r],tr[lca],tr[ff],1,m,k)]);
}
return 0;
}
P2633 Count on a tree(主席树)的更多相关文章
- 洛谷P2633 Count on a tree(主席树上树)
题目描述 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权.其中lastans是上一个询问的答案,初始为0,即第一个 ...
- 洛谷 P2633 Count on a tree 主席树
在一棵树上,我们要求点 $(u,v)$ 之间路径的第$k$大数. 对于点 $i$ ,建立 $i$ 到根节点的一棵前缀主席树. 简单容斥后不难得出结果为$sumv[u]+sumv[v]−sumv[l ...
- 洛谷P2633 Count on a tree 主席树
传送门:主席树 解题报告: 传送门! umm这题我还麻油开始做 所以 先瞎扯一波我的想法,如果错了我就当反面教材解释这种典型错误,对了我就不管了QwQ 就直接dfs,在dfs的过程中建树 然后就直接查 ...
- 洛谷P2633/bzoj2588 Count on a tree (主席树)
洛谷P2633/bzoj2588 Count on a tree 题目描述 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K ...
- 【BZOJ-2588】Count on a tree 主席树 + 倍增
2588: Spoj 10628. Count on a tree Time Limit: 12 Sec Memory Limit: 128 MBSubmit: 3749 Solved: 873[ ...
- spoj cot: Count on a tree 主席树
10628. Count on a tree Problem code: COT You are given a tree with N nodes.The tree nodes are number ...
- Bzoj 2588: Spoj 10628. Count on a tree 主席树,离散化,可持久,倍增LCA
题目:http://www.lydsy.com/JudgeOnline/problem.php?id=2588 2588: Spoj 10628. Count on a tree Time Limit ...
- 【BZOJ2588】Spoj 10628. Count on a tree 主席树+LCA
[BZOJ2588]Spoj 10628. Count on a tree Description 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lasta ...
- SPOJ Count on a tree(主席树+LCA)
一.题目 COT - Count on a tree You are given a tree with N nodes. The tree nodes are numbered from 1 to ...
随机推荐
- Win10运行在哪里,Win10的运行怎么打开
方法/步骤 1 唯一的方法是同时按下WIN+X键组合,如下图所示 步骤阅读 2 在弹出菜单可以看到运行了!如下图所示 步骤阅读 3 运行对话框出来了,如下图所示 步骤阅读 4 还有一个方法,点击桌面左 ...
- LeetCode Golang实现 1. 两数之和
1. 两数之和 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标. 你可以假设每种输入只会对应一个答案.但是,你不能重复利用这 ...
- IDEA创建Maven项目显示一直加载中的问题
使用IDEA这款工具创建Maven项目的时候出现过下面这种情况: 红色区域即maven骨架加载不出来... 或 loading loading loading ... 有时候需要很长一段时间才能加载出 ...
- du -sh*查看当前目录下的文件夹大小
du -sh*查看当前目录下的文件夹大小 u 命令 用途 概述磁盘使用. 语法 du [ -a | -s ] [ -k ] [ -m ] [ -g ][ -l ] [ -r ] ...
- window下搭建Python3.7+selenium3.1.1+pycharm环境
1.安装Python3.7 1.1 下载 Python并安装 Python3.5 (勾选上 Add Python3.7 to PATH) 点击 Install Now,安装完成后将python路径加 ...
- 题解 P3413 【SAC#1 - 萌数】
这道题刚开始正向思维,然后处理重复的时候咕咕了. 参考了@巨型方块 大佬的题解后AC了,在这里就说几个我觉得比较重要或是容易被忽略的点,然后补充一些跳过的证明. 这道题的状态可以设为$dp[i][j] ...
- mysql给某字段随机赋特定范围的整数值
[引] mysql中随机生成一些范围内的整数有时候是很有用的,用到了2个函数 1.floor(f) 返回一个不大于f的最大整数 2.rand(),rand(n) 返回一个随机浮点值 v ,范围在 0 ...
- 基于SpringMVC+Bootstrap+DataTables实现表格服务端分页、模糊查询
前言 基于SpringMVC+Bootstrap+DataTables实现数据表格服务端分页.模糊查询(非DataTables Search),页面异步刷新. 说明:sp:message标签是使用了S ...
- 如何检查 Android 应用的内存使用情况
Android是为移动设备而设计的,所以应该关注应用的内存使用情况.尽管Android的Dalvik虚拟机会定期执行垃圾回收操作,但这也不意味着就可以忽视应用在何时何处进行内存分配和释放.为了提供良好 ...
- [Android] 使用Matrix矩阵类对图像进行缩放、旋转、对照度、亮度处理
前一篇文章讲述了Android拍照.截图.保存并显示在ImageView控件中,该篇文章继续讲述Android图像处理技术,主要操作包含:通过打开相冊里的图片,使用Matrix对图像进行缩放. ...