链接:

https://www.spoj.com/problems/COT/en/

思路:

首先看到求两点之前的第k小很容易想到用主席树去写,但是主席树处理的是线性结构,而这道题要求的是树形结构,我们可以用dfs跑出所有点离根的距离-dep[i](根为1,dep[1]也为1)在dfs的过程

中,我们对每一个节点建一棵线段树,那么【a,b】就是:root[a] + root[b] - root[lca(a,b)] - root[f[lca(a,b)]]; (因为a-b的路径上的权值还要算上lca(a,b)这个点,所以不是减2*root[lca(a,b)]);

实现代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define mid int m = (l + r) >> 1
const int M = 2e5 + ;
int p[M][],dep[M],head[M],sum[M*],ls[M*],rs[M*],root[M*];
int cnt1,n,idx,cnt,f[M]; struct node {
int to,next;
}e[M]; void add(int u,int v){
e[++cnt1].to=v;e[cnt1].next=head[u];head[u]=cnt1;
e[++cnt1].to=u;e[cnt1].next=head[v];head[v]=cnt1;
} int lca(int a,int b){
if(dep[a] > dep[b]) swap(a,b);
int h = dep[b] - dep[a]; //h为高度差
for(int i = ;(<<i)<=h;i++){ //(1<<i)&f找到h化为2进制后1的位置,移动到相应的位置
if((<<i)&h) b = p[b][i];
//比如h = 5(101),先移动2^0祖先,然后再移动2^2祖先
}
//cout<<a<<" "<<b<<endl;
if(a!=b){
for(int i = ;i >= ;i --){
if(p[a][i]!=p[b][i]){ //从最大祖先开始,判断a,b祖先,是否相同
a = p[a][i]; b = p[b][i]; //如不相同,a,b,同时向上移动2^j
}
}
a = p[a][]; //这时a的father就是LCA
}
return a;
} void build(int l,int r,int &rt){
rt = ++idx;
sum[rt] = ;
if(l == r) return;
mid;
build(l,m,ls[rt]);
build(m+,r,rs[rt]);
} void update(int p,int l,int r,int old,int &rt){
rt = ++idx;
ls[rt] = ls[old]; rs[rt] = rs[old]; sum[rt] = sum[old] + ;
if(l == r) return ;
mid;
if(p <= m) update(p,l,m,ls[old],ls[rt]);
else update(p,m+,r,rs[old],rs[rt]);
} int query(int a,int b,int lc,int cl,int l,int r,int k){
if(l == r) return l;
mid;
int cnt = sum[ls[a]] + sum[ls[b]] - sum[ls[lc]] - sum[ls[cl]];
if(k <= cnt)
return query(ls[a],ls[b],ls[lc],ls[cl],l,m,k);
else
return query(rs[a],rs[b],rs[lc],rs[cl],m+,r,k-cnt);
}
int a[M],b[M]; void dfs(int u,int fa){
f[u] = fa;
dep[u] = dep[fa] + ;
p[u][] = fa;
for(int i = ;i < ;i ++) p[u][i] = p[p[u][i-]][i-];
update(a[u],,cnt,root[fa],root[u]);
for(int i = head[u];i!=-;i = e[i].next){
int v = e[i].to;
if(v == fa) continue;
dfs(v,u);
}
} int main()
{
int m;
while(scanf("%d%d",&n,&m)!=EOF){
cnt1 = ;
memset(head,-,sizeof(head));
memset(dep,,sizeof(dep));
memset(p,,sizeof(p));
memset(f,,sizeof(f));
for(int i = ; i <= n;i ++){
scanf("%d",&a[i]);
b[i] = a[i];
}
idx = ;
int l,r,c;
sort(b+,b+n+);
cnt = unique(b+,b++n)-b-;
for(int i = ;i <= n;i ++)
a[i] = lower_bound(b+,b+cnt+,a[i]) - b;
for(int i = ;i <= n-;i ++){
scanf("%d%d",&l,&r);
add(l,r);
}
build(,cnt,root[]);
dfs(,);
for(int i = ;i <= m;i ++){
scanf("%d%d%d",&l,&r,&c);
int lc = lca(l,r);
int id = query(root[l],root[r],root[lc],root[f[lc]],,cnt,c);
printf("%d\n",b[id]);
}
}
return ;
}

spoj COT - Count on a tree (树上第K小 LCA+主席树)的更多相关文章

  1. E - Count on a tree 树上第K小

    主席树的入门题目,这道题的题意其实就是说,给你一棵树,询问在两个节点之间的路径上的区间第K小 我们如何把树上问题转换为区间问题呢? 其实DFS就可以,我们按照DFS的顺序,对线段树进行建树,那么这个树 ...

  2. SPOJ - COT Count on a tree

    地址:http://www.spoj.com/problems/COT/en/ 题目: COT - Count on a tree #tree You are given a tree with N  ...

  3. BZOJ 2588: Spoj 10628. Count on a tree [树上主席树]

    2588: Spoj 10628. Count on a tree Time Limit: 12 Sec  Memory Limit: 128 MBSubmit: 5217  Solved: 1233 ...

  4. BZOJ 2588: Spoj 10628. Count on a tree 树上跑主席树

    2588: Spoj 10628. Count on a tree Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/J ...

  5. SPOJ COT Count on a tree(树上主席树 + LCA 求点第k小)题解

    题意:n个点的树,每个点有权值,问你u~v路径第k小的点的权值是? 思路: 树上主席树就是每个点建一棵权值线段树,具体看JQ博客,LCA用倍增logn求出,具体原理看这里 树上主席树我每个点的存的是点 ...

  6. 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 ...

  7. SPOJ 10628. SPOJ COT Count on a tree 可持久化线段树

    这题是裸的主席树,每个节点建一棵主席树,再加个lca就可以了. 历尽艰辛,终于A掉了这一题,这般艰辛也显示出了打代码的不熟练. 错误:1.lca倍增的时候i和j写反了,RE了5次,实在要吸取教训 2. ...

  8. spoj COT - Count on a tree(主席树 +lca,树上第K大)

    您将获得一个包含N个节点的树.树节点的编号从1到Ñ.每个节点都有一个整数权重. 我们会要求您执行以下操作: uvk:询问从节点u到节点v的路径上的第k个最小权重 输入 在第一行中有两个整数Ñ和中号.( ...

  9. SPOJ 10628 COT - Count on a tree(在树上建立主席树)(LCA)

    COT - Count on a tree #tree You are given a tree with N nodes.The tree nodes are numbered from 1 to ...

随机推荐

  1. 如何扩展32位EXE程序的使用内存

    1 运行Visual studio的命令行,执行下面命令:editbin /LARGEADDRESSAWARE “C:\Program Files\Skyline\TerraExplorer Pro\ ...

  2. 使用Quartz实现定时任务

    一:Quertz的用途 Quertz是一个开源的作业任务调度框架,他可以完成像JavaScript定时器类式的功能,其实Java中Timer也可实现部分功能,但相比Quertz还是略逊一筹,本人这次需 ...

  3. Luogu2839 Middle 主席树、二分答案

    题目传送门:https://www.luogu.org/problemnew/show/P2839 题目大意:给出一个长度为$N$的序列与$Q$次询问,每次询问左端点在$[a,b]$,右端点在$[c, ...

  4. vue 动态创建组件(运行时创建组件)

    function mountCmp (cmp, props, parent) { if (cmp.default) { cmp = cmp.default } cmp = Vue.extend(cmp ...

  5. 数据库日志——mysql与Oracle的日志

    一.MySQL 在数据同步中用的比较多的是MySQL的binlog 1.bin-log简介 它记录了所有的DDL和DML(除了数据查询语句,select与show不记录)语句,以事件形式记录,还包含语 ...

  6. 机器学习sklearn19.0聚类算法——Kmeans算法

    一.关于聚类及相似度.距离的知识点 二.k-means算法思想与流程 三.sklearn中对于kmeans算法的参数 四.代码示例以及应用的知识点简介 (1)make_blobs:聚类数据生成器 sk ...

  7. Scala学习(八)---Scala继承

    Scala继承 摘要: 在本篇中,你将了解到Scala的继承与Java和C++最显著的不同.要点包括: 1. extends.final关键字和Java中相同 2. 重写方法时必须用override ...

  8. Spring Cloud 入门教程(五): Ribbon实现客户端的负载均衡

    接上节,假如我们的Hello world服务的访问量剧增,用一个服务已经无法承载, 我们可以把Hello World服务做成一个集群. 很简单,我们只需要复制Hello world服务,同时将原来的端 ...

  9. Linux查看日志常用命令

    1.动态循环查看文件内容 tail  -n  10  test.log   查询日志尾部最后10行的日志; tail -n +10 test.log    查询10行之后的所有日志; head -n ...

  10. git使用(2)

    1.远程仓库 a SSHKEY 第1步:创建SSH Key.在用户主目录下,看看有没有.ssh目录,如果有,再看看这个目录下有没有id_rsa和id_rsa.pub这两个文件,如果已经有了,可直接跳到 ...