树上第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 ...
随机推荐
- 4.Swift教程翻译系列——Swift基本运算符
英文版PDF下载地址http://download.csdn.net/detail/tsingheng/7480427 运算符是指一个特殊的符号,能够用来查看.更改值或者相加.比方说加法运算符+能够讲 ...
- 终于懂了:Delphi消息的Result域出现的原因——要代替回调函数的返回值!(MakeObjectInstance不会帮助处理(接收)消息回调函数的返回值)
MakeObjectInstance应该不会帮助处理(接收)消息回调函数的返回值,可是有时候又确实需要这个返回值,这可怎么办呢?我是看到这段文字的时候,想到这个问题的: 当WM_PAINT不是由Inv ...
- MP3文件的结构与编程
有一个朋友喜欢听MP3,为了获取MP3,写了一个程序,专门从一家音乐网站上搜索下载mp3,一下子下载了有上千首.这时朋友又犯愁了,这些MP3的歌曲名字都是使用1,2,3,4,..等数字命名,挑选起来十 ...
- flashcache中应用device mapper机制
Device Mapper(DM)是Linux 2.6全面引入的块设备新构架,通过DM可以灵活地管理系统中所有的真实或虚拟的块设备. DM以块设备的形式注册到Linux内核中,凡是挂载(或者说“映射” ...
- Swift - 自定义单元格实现微信聊天界面
1,下面是一个放微信聊天界面的消息展示列表,实现的功能有: (1)消息可以是文本消息也可以是图片消息 (2)消息背景为气泡状图片,同时消息气泡可根据内容自适应大小 (3)每条消息旁边有头像,在左边表示 ...
- SpringMVC存取Session的两种方法
方法一:使用servlet-api @Controller public class ManagerController { @Resource private ManagerService mana ...
- CountDownLatch和CyclicBarrier的区别(转)
在网上看到很多人对于CountDownLatch和CyclicBarrier的区别简单理解为CountDownLatch是一次性的,而CyclicBarrier在调用reset之后还可以继续使用.那如 ...
- Unity3D游戏开发之开发游戏带来的问题
昨日曾就某投资人把移动团队失败原因之中的一个归于选择Unity引擎进行了一番评论,工具本身无罪,但怎样理解工具.正确使用Unity引擎确实须要讨论,在选择Unity之前你也许须要了解下这个引擎实际开发 ...
- 实现Runnable接口和扩展Thread使用场景
在上篇博文:java学习笔记-Thread中我们知道创建子线程的两个方式:实现Runnable接口和扩展Thread. 扩展Thread类和实现Runnable接口的使用场景: Thread类定义了派 ...
- WinCE隐藏显示任务栏,当任务栏隐藏时将其显示,当任务栏显示时将其隐藏(FindWindow,ShowWindow,IsWindowVisible),
HANDLE hWndTaskBar = ::FindWindow(TEXT("HHTaskBar"), NULL); if(::IsWindowVisible(hWndTask ...