树上第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 ...
随机推荐
- SDUT Fermat’s Chirstmas Theorem(素数筛)
Fermat's Chirstmas Theorem Time Limit: 1000ms Memory limit: 65536K 有疑问?点这里^_^ 题目描写叙述 In a letter ...
- CImage类
CImage封装了DIB(设备无关位图)的功能,因而可以让我们能够处理每个位图像素.这里介绍GDI+和CImage的一般使用方法和技巧. TAG: GDI CImage 后处理 我们知道,Vi ...
- 暂停和屏蔽右键网页中的Flash
如何暂停网页中的Flash?原理很简单,就是屏蔽Flash的消息即可.屏蔽右键也可以通过此方法 直接贴代码吧,加了注释,很容易就能懂了 新建工程,加一个WebBrowser,再加两个按钮.Flash ...
- 【设计模式】Singleton模式C++实现
Singleton是设计模式中比较简单的一个.园中的朋友们应该都很熟悉了.前段时间参加xxx外企的面试,和面试官讨论C++的时候正好写了一个.当时由于在有些地方考虑不太周全,代码出现了一些疏漏.不过最 ...
- Missing artifact net.sf.json-lib:json-lib:jar:2.2.3:compile
json-lib是需要区分jdk版本的,pom.xml中的配置应加上<classifier>标签,如用jdk15: <dependency> <groupId>ne ...
- c++实用技巧
原地址:http://www.cnblogs.com/easymind223/articles/2576904.html 晚上的时间总是习惯性的在cnblogs逛街,今天又看到了好文章,其c++味道浓 ...
- [IDEs]Eclipse设置花括号样式
用惯Vistual Studio,在使用Eclipse时发现有很多东西还是挺不习惯,第一个就要解决花括号的样式 步骤: 1.Windows->Preferences->Java->C ...
- [Cocos2d-x]Android的android.mk文件通用版本
原文地址: http://blog.ready4go.com/blog/2013/10/12/update-android-dot-mk-with-local-src-files-and-local- ...
- 事务应用-运行多条SQL语句
事务具有原子性,要么不运行,要么全运行,一旦成功运行永久保存.而这些正是因为事务的原子性和对数据库的持久性形成的.下面是一个关于统一给数据库中的数据改动的批量操作,利用到事务. TODO:批量改动数据 ...
- POJ 1325 ZOJ 1364 最小覆盖点集
题意:有A,B两台机器, 机器A 有 n个模式(0, 1, 2....n-1),同样机器B有m个模式, 两个机器一开始的模式都为0,有k个作业(id,x,y) 表示作业编号id, 该作业必须在A机器在 ...