树上第k小,可持久化线段树+倍增lca
给定一颗树,树的每个结点都有权值,
有q个询问,每个询问是 u v k ,表示u到v路径上第k小的权值是多少。
每个结点所表示的线段树,是父亲结点的线段树添加该结点的权值之后形成的新的线段树
c[root] 表示根为root的子树添加了多少个结点。
那么c[lson[u]] + c[lson[v]] - c[lson[lca(u,v)]] - c[lson[fa[lca(u,v)]]] >=k ,那么说明左子树添加了k个以上的结点,说明第k小的值在左子树
否则就在右子树。
//
// main.cpp
// 函数式线段树
//
// Created by whoami on 15/9/21.
// Copyright (c) 2015年 whoami. All rights reserved.
// #include <iostream>
#include <algorithm>
#include <stdio.h>
#include <string.h>
using namespace std;
const int N = + ;
const int M = ;
int t[N],lson[N],rson[N],c[N],total;
int a[M],b[M];
int n,m,q;
int head[M],nxt[M],to[M],e;
int dfs_clock,iid[M];
int fa[M][],depth[M];
void addEdge(int u, int v){
to[e] = v;
nxt[e] = head[u];
head[u] = e++;
} //离散化,离散化后有多少个点,线段树的区间就是多大
void initHash(){
sort(b+,b+n+);
m = unique(b+,b+n+) - b - ;
}
int hs(int x){
return lower_bound(b+,b+m+,x)-b;
} int build(int l, int r){
int root = total++;
c[root] = ;
if(l!=r){
int mid = (l+r)>>;
lson[root] = build(l,mid);
rson[root] = build(mid+,r);
}
return root;
}
int update(int root, int pos, int val){
int newRoot = total++,tmp = newRoot;
c[newRoot] = c[root] + val;
int l =, r = m;
while(l<r){
int mid = (l+r)>>;
if(pos<=mid){
r = mid;
lson[newRoot] = total++;
rson[newRoot] = rson[root];
newRoot = lson[newRoot];
root = lson[root];
}
else{
l = mid + ;
lson[newRoot] = lson[root];
rson[newRoot] = total++;
newRoot = rson[newRoot];
root = rson[root];
}
c[newRoot] = c[root] + val;
}
return tmp;
}
void dfs(int u, int f, int dep){
fa[u][] = f;
depth[u] = dep; for(int i=head[u]; i+;i=nxt[i]){
int v = to[i];
if(v==f)continue;
t[++dfs_clock] = update(iid[u],hs(a[v]),);
iid[v] = t[dfs_clock];
dfs(v,u,dep+);
}
} int query(int urt, int vrt, int lcart, int frt, int k){
int l = , r = m;
//当l==r,即区间的长度只有1时,那么该区间所对应的值就是第k小了
while(l<r){
int mid = (l+r)>>;
if(c[lson[urt]] + c[lson[vrt]] - c[lson[frt]]-c[lson[lcart]]>=k){
r = mid;
urt = lson[urt];
vrt = lson[vrt];
frt = lson[frt];
lcart = lson[lcart];
}
else
{
l = mid+;
k -= c[lson[urt]] + c[lson[vrt]] - c[lson[frt]]-c[lson[lcart]];
urt = rson[urt];
vrt = rson[vrt];
frt = rson[frt];
lcart = rson[lcart];
}
}
return l;
}
void init() {
for(int k=;k+<; ++k){
for(int v = ;v<=n;++v){
if(fa[v][k]<)
fa[v][k+] = -;
else
fa[v][k+] = fa[fa[v][k]][k];
}
}
} int lca(int u, int v){
if(depth[u] < depth[v])
swap(u,v); int tmp = depth[u] - depth[v];
for(int i=;i>=;--i)
if(tmp &(<<i))
u = fa[u][i];
if(u==v) return u;
for(int i=;i>=;--i){
if(fa[u][i]!=fa[v][i]){
u = fa[u][i];
v = fa[v][i];
}
}
return fa[u][]; }
int main(int argc, const char * argv[]) {
int u,v,k;
while(scanf("%d%d",&n,&q)!=EOF){
total = dfs_clock = ;
for(int i=;i<=n;++i){
scanf("%d",&a[i]);
b[i] = a[i];
}
memset(head,-,sizeof(head));
for(int i=;i<n;++i){
scanf("%d%d",&u,&v);
addEdge(u,v);
addEdge(v,u);
}
addEdge(,);
addEdge(,);
initHash();
iid[] = t[] = build(,m);
memset(fa,-,sizeof(fa));
dfs(,,); init();
while(q--){
scanf("%d%d%d",&u,&v,&k);
int lc = lca(u,v);
int f = fa[lc][];
printf("%d\n",b[query(iid[u],iid[v],iid[lc],iid[f],k)]);
}
} return ;
}
树上第k小,可持久化线段树+倍增lca的更多相关文章
- POJ- 2104 hdu 2665 (区间第k小 可持久化线段树)
可持久化线段树 也叫函数式线段树也叫主席树,其主要思想是充分利用历史信息,共用空间 http://blog.sina.com.cn/s/blog_4a0c4e5d0101c8fr.html 这个博客总 ...
- 区间第K小——可持久化线段树模板
概念 可持久化线段树又叫主席树,之所以叫主席树是因为这东西是fotile主席创建出来的. 可持久化数据结构思想,就是保留整个操作的历史,即,对一个线段树进行操作之后,保留访问操作前的线段树的能力. 最 ...
- 序列内第k小查询(线段树)
最近请教了一下大佬怎么求序列内第k大查询,自己又捣鼓了一下,虽然还没有懂得区间第k大查询,不过姑且做一个记录先吧 因为每个元素大小可能很大而元素之间不连续,所以我们先离散化处理一下,程序中的ori[ ...
- HDU 2665.Kth number-可持久化线段树(无修改区间第K小)模板 (POJ 2104.K-th Number 、洛谷 P3834 【模板】可持久化线段树 1(主席树)只是输入格式不一样,其他几乎都一样的)
Kth number Time Limit: 15000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total ...
- SPOJ-COT-Count on a tree(树上路径第K小,可持久化线段树)
题意: 求树上A,B两点路径上第K小的数 分析: 同样是可持久化线段树,只是这一次我们用它来维护树上的信息. 我们之前已经知道,可持久化线段树实际上是维护的一个前缀和,而前缀和不一定要出现在一个线性表 ...
- 计蒜客 38229.Distance on the tree-1.树链剖分(边权)+可持久化线段树(区间小于等于k的数的个数)+离散化+离线处理 or 2.树上第k大(主席树)+二分+离散化+在线查询 (The Preliminary Contest for ICPC China Nanchang National Invitational 南昌邀请赛网络赛)
Distance on the tree DSM(Data Structure Master) once learned about tree when he was preparing for NO ...
- 【可持久化线段树】POJ2104 查询区间第k小值
K-th Number Time Limit: 20000MS Memory Limit: 65536K Total Submissions: 61284 Accepted: 21504 Ca ...
- [TS-A1505] [清橙2013中国国家集训队第二次作业] 树 [可持久化线段树,求树上路径第k大]
按Dfs序逐个插入点,建立可持久化线段树,每次查询即可,具体详见代码. 不知道为什么,代码慢的要死,, #include <iostream> #include <algorithm ...
- BZOJ 2588: Spoj 10628. Count on a tree-可持久化线段树+LCA(点权)(树上的操作) 无语(为什么我的LCA的板子不对)
2588: Spoj 10628. Count on a tree Time Limit: 12 Sec Memory Limit: 128 MBSubmit: 9280 Solved: 2421 ...
随机推荐
- asp.net web api帮助文档的说明
为asp.net的mvc web api填写自己的帮助文档 1. 加入Help的area(能够通过命令行或其它方式加入) 命令行:Install-Package Microsoft.AspNet.We ...
- MFC的消息反射机制
1.消息反射解释: 父窗口将子窗口发给它的通知消息,首先反射回子窗口进行处理(即给子窗口一个机会,让子窗口处理此消息),这样通知消息就有机会能被子窗口自身进行处理. 2.MFC中引入消息反射的原因: ...
- Delphi -- 创建 桌面、发送到...、快速启动栏、开始菜单、程序菜单、右键菜 单
{================================================================= 功 能: 创建 桌面.发送到....快速启动栏.开始菜单.程序菜单 ...
- QT解析命令行(QCommandLineOption和QCommandLineParser类)
Qt从5.2版开始提供了两个类QCommandLineOption和QCommandLineParser来解析应用的命令行参数. 一.命令行写法命令行:"-abc" 在QComma ...
- Lucene.Net 2.3.1开发介绍 —— 四、搜索(一)
原文:Lucene.Net 2.3.1开发介绍 -- 四.搜索(一) 既然是内容筛选,或者说是搜索引擎,有索引,必然要有搜索.搜索虽然与索引有关,那也只是与索引后的文件有关,和索引的程序是无关的,因此 ...
- 测试关闭mojo utf-8
[root@wx03 ~]# cat test.pl use Mojolicious::Lite; use JSON qw/encode_json decode_json/; use Encode; ...
- Wayland中的跨进程过程调用浅析
原文地址:http://blog.csdn.net/jinzhuojun/article/details/40264449 Wayland协议主要提供了Client端应用与Server端Composi ...
- Silverlight 5(C#)初探
接了个单子,非要用Silverlight 5来作一个项目,之前从来没接触过这东西,为了工作.硬着头皮也要上了.摸索了一晚上,大至整理出一些项目中须要的东西,下面作为初探记录: Silverlight ...
- boost库在工作(33)网络服务端之三
在这个例子里,表示服务器与一个客户端的沟通渠道,就是一个连接,封装为类CConnect.它是当服务器接收到一个客户端连接请求之后创建的,主要用来就是管理这个连接的生命周期,以及数据的接收和发送.从生命 ...
- Android 异步链式调用设计
本文讨论一下异步链式调用的设计与实现. 考虑如下情况: 情况1: 访问网络(或其他耗时的事情).通常的做法是: 1.显示一个ProgressDialog对话框,提示用户. 2.启动工作线程来执行耗时操 ...