【传送门:caioj1443


简要题意:

  给出一颗n个点的树,给出每个点的权值,再给出n-1条边,有m个询问,每个询问输入x,y,k,输出第x节点到第y节点的路径上第k大的点


题解:

  这是一道主席树的例题,感觉很想用树链剖分,但是会超时吧......

  做法就是将每个点到树的根所形成的链建立线段树,然后dfs找出点与点之间的父子关系,每个点都将自己和自己的父亲,自己的父亲的父亲....直到根所组成的所有线段树合并起来,然后就可以得到能够代表区间的主席树了,然后每当询问输入x,y时,就先找x和y的最近公共祖先(倍增LCA来求),然后x和y的路径其实就是x到根的路径加上y到根的路径,然后减去最近公共祖先到根的路径,再减去最近公共祖先的父亲到根的路径(为什么是最近公共祖先的父亲呢,因为如果是再减去最近公共祖先到根的路径的话,最近公共祖先就会被除去,这样是不对的,所以减去最近公共祖先的父亲到根的路径)


参考代码:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
int s[],ss[];
struct trnode
{
int lc,rc,c;
}tr[];int cnt;
int rt[];
struct edge
{
int x,y,next;
}a[];int len,last[];
void ins(int x,int y)
{
len++;
a[len].x=x;a[len].y=y;
a[len].next=last[x];last[x]=len;
}
int n;
int LS(int d)
{
int l=,r=n,ans=;
while(l<=r)
{
int mid=(l+r)/;
if(s[mid]<=d)
{
ans=mid;
l=mid+;
}
else r=mid-;
}
return ans;
}
void Link(int &u,int l,int r,int p)
{
if(u==) u=++cnt;
tr[u].c++;
if(l==r) return ;
int mid=(l+r)/;
if(p<=mid) Link(tr[u].lc,l,mid,p);
else Link(tr[u].rc,mid+,r,p);
}
void Merge(int &u1,int u2)
{
if(u1==){u1=u2;return ;}
if(u2==) return ;
tr[u1].c+=tr[u2].c;
Merge(tr[u1].lc,tr[u2].lc);
Merge(tr[u1].rc,tr[u2].rc);
}
int dep[];
int f[][];
int LCA(int x,int y)
{
if(dep[x]<dep[y]) swap(x,y);
for(int i=;i>=;i--) if(dep[x]-dep[y]>=(<<i)) x=f[x][i];
if(x==y) return x;
for(int i=;i>=;i--)
if(dep[x]>=(<<i)&&f[x][i]!=f[y][i])
{
x=f[x][i];y=f[y][i];
}
return f[x][];
}
void bt(int x,int fa)
{
dep[x]=dep[fa]+;
f[x][]=fa;
for(int i=;(<<i)<=dep[x];i++) f[x][i]=f[f[x][i-]][i-];
Merge(rt[x],rt[fa]);
for(int k=last[x];k;k=a[k].next)
{
int y=a[k].y;
if(y!=fa)
{
bt(y,x);
}
}
}
int Ask(int u1,int u2,int u3,int u4,int l,int r,int p)
{
if(l==r) return s[l];
int c=tr[tr[u1].lc].c+tr[tr[u2].lc].c-tr[tr[u3].lc].c-tr[tr[u4].lc].c;
int mid=(l+r)/;
if(p<=c) return Ask(tr[u1].lc,tr[u2].lc,tr[u3].lc,tr[u4].lc,l,mid,p);
else return Ask(tr[u1].rc,tr[u2].rc,tr[u3].rc,tr[u4].rc,mid+,r,p-c);
}
int main()
{
int m;
scanf("%d%d",&n,&m);
cnt=;memset(rt,,sizeof(rt));
for(int i=;i<=n;i++)
{
scanf("%d",&ss[i]);
s[i]=ss[i];
}
sort(s+,s+n+);
len=;memset(last,,sizeof(last));
for(int i=;i<n;i++)
{
int x,y;
scanf("%d%d",&x,&y);
ins(x,y);ins(y,x);
}
cnt=;
for(int i=;i<=n;i++) Link(rt[i],,n,LS(ss[i]));
dep[]=;bt(,);
for(int i=;i<=m;i++)
{
int x,y,k;
scanf("%d%d%d",&x,&y,&k);
int lca=LCA(x,y);
printf("%d\n",Ask(rt[x],rt[y],rt[lca],rt[f[lca][]],,n,k));
}
return ;

caioj1443:第k小的数Ⅲ的更多相关文章

  1. *HDU2852 树状数组(求第K小的数)

    KiKi's K-Number Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)T ...

  2. 计算序列中第k小的数

    作者:jostree 转载请注明出处 http://www.cnblogs.com/jostree/p/4046399.html 使用分治算法,首先选择随机选择轴值pivot,并使的序列中比pivot ...

  3. [LeetCode] Find K-th Smallest Pair Distance 找第K小的数对儿距离

    Given an integer array, return the k-th smallest distance among all the pairs. The distance of a pai ...

  4. #7 找出数组中第k小的数

    「HW面试题」 [题目] 给定一个整数数组,如何快速地求出该数组中第k小的数.假如数组为[4,0,1,0,2,3],那么第三小的元素是1 [题目分析] 这道题涉及整数列表排序问题,直接使用sort方法 ...

  5. 无序数组求第k大/第k小的数

    根据http://www.cnblogs.com/zhjp11/archive/2010/02/26/1674227.html 博客中所总结的7种解法,我挑了其中的解法3和解法6进行了实现. 解法3: ...

  6. 查找第K小的数 BFPRT算法

    出处 http://blog.csdn.net/adong76/article/details/10071297 BFPRT算法是解决从n个数中选择第k大或第k小的数这个经典问题的著名算法,但很多人并 ...

  7. 基于快速排序思想partition查找第K大的数或者第K小的数。

    快速排序 下面是之前实现过的快速排序的代码. function quickSort(a,left,right){ if(left==right)return; let key=partition(a, ...

  8. 算法---数组总结篇2——找丢失的数,找最大最小,前k大,第k小的数

    一.如何找出数组中丢失的数 题目描述:给定一个由n-1个整数组成的未排序的数组序列,其原始都是1到n中的不同的整数,请写出一个寻找数组序列中缺失整数的线性时间算法 方法1:累加求和 时间复杂度是O(N ...

  9. cogs930找第k小的数(k-th number)

    cogs930找第k小的数(k-th number) 原题链接 题解 好题... 终极版是bzoj3065(然而并不会) 先讲这个题... 维护\(n+1\)个值域线段树(用主席树),标号\(0\) ...

随机推荐

  1. 【BZOJ4016】【FJOI2014】最短路径树问题

    题意: Description 给一个包含n个点,m条边的无向连通图.从顶点1出发,往其余所有点分别走一次并返回. 往某一个点走时,选择总长度最短的路径走.若有多条长度最短的路径,则选择经过的顶点序列 ...

  2. luogu P4430 小猴打架(prufer编码与Cayley定理)

    题意 n个点问有多少种有顺序的连接方法把这些点连成一棵树. (n<=106) 题解 了解有关prufer编码与Cayley定理的知识. 可知带标号的无根树有nn-2种.然后n-1条边有(n-1) ...

  3. thinkphp 5.0整合phpsocketio完整攻略,绕坑

    使用环境: thinkphp5.0 项目需求 前端下单,后台接受,并立即做出提示.例如:美团外卖,客户端下单成功后,商家端就会立即有接单语音提示. 开发环境 thinkphp5.0 phpsocket ...

  4. 洛谷 P1373 小a和uim之大逃离 (差值型dp总结)

    这道题和多米诺骨牌那道题很像 ,都是涉及到差值的问题. 这道题是二维的,同时要取模. 这种题,因为当前的决策有后效性,会影响到差值,所以直接把 差值作为维度,然后计算答案的时候把差值为0的加起来就行了 ...

  5. 紫书 习题 8-15 UVa 1617 (贪心)

    先排序, 然后每个线段先放右端点, 然后往下放, 如果不能放就整体往左移动, 当不能往左移动的时候就ans++ 开始下一个整块.判断能不能向左移动要用一个变量储存每个已经放了的区间中线段与左端点距离的 ...

  6. Mysql学习总结(26)——MySQL子查询

    mysql中虽然有连接查询实现多表连接查询,但是连接查询的性能很差,因此便出现了子查询. 1.理论上,子查询可以出现在查询语句的任何位置,但实际应用中多出现在from后和where后.出现在from后 ...

  7. 2015 Multi-University Training Contest 2 hdu 5306 Gorgeous Sequence

    Gorgeous Sequence Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Othe ...

  8. hadoop-05-mysql修改密码

    hadoop-05-mysql修改密码 su root 1,service mysqld start 2,vi /var/log/mysqld.log #在这里面查找密码 3, mysql -uroo ...

  9. css 清楚浮动的8种方式

    清除浮动是每个 web前台设计师必须掌握的机能. css清除浮动大全,共8种方法. 浮动会使当前标签产生向上浮的效果,同一时候会影响到前后标签.父级标签的位置及 width height 属性.并且相 ...

  10. vncserverpassword改动

    前几天去客户现场,客户说有測试库.Linux下的,帮忙给新建一个数据库,我这么热心的人.是吧 那就開始吧. 一般使用vnc搞图形安装.熟练的打开vnc.输入password,报错!!我愣了几秒,忽然反 ...