Time Limit: 129MS   Memory Limit: 1572864KB   64bit IO Format: %lld & %llu

Submit Status

Description

You are given a tree with N nodes.The tree nodes are numbered from 1 to N.Each node has an integer weight.

We will ask you to perform the following operation:

  • u v k : ask for the kth minimum weight on the path from node u to node v

Input

In the first line there are two integers N and M.(N,M<=100000)

In the second line there are N integers.The ith integer denotes the weight of the ith node.

In the next N-1 lines,each line contains two integers u v,which describes an edge (u,v).

In the next M lines,each line contains three integers u v k,which means an operation asking for the kth minimum weight on the path from node u to node v.

Output

For each operation,print its result.

Example

Input:
8 5
8 5
105 2 9 3 8 5 7 7
1 2
1 3
1 4
3 5
3 6
3 7
4 8
2 5 1
2 5 2
2 5 3
2 5 4
7 8 2 
Output:
2
8
9
105

题意:求树上的边[u,v]中点权第k大

使用的是主席树+LCA(RMQ.dfs),然后去专门看了下RMQ+dfs实现LCA

用一个数组记录深度,然后记录搜索的路径,如果要找[a,b]中的LCA,直接找[a,b]中的深度最小值即可

参考:算法之LCA与RMQ问题

/*
主席树-代码参考kuangbin大神
在本题中相当于按树的节点来构建线段树,每个节点基于它的父亲进行构建
然后节点a保存的便是根到a的情况,于是乎我们T[a]+T[b]-2*T[lca(a,b)]即可
而且对lca节点进行一个判断。
hhh-2016-02-18 21:11:14
*/ #include <functional>
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <map>
#include <cmath>
using namespace std; const int maxn = 200010;
int n,m;
int a[maxn],t[maxn];
int T[maxn*40],val[maxn*40],lson[maxn*40],rson[maxn*40];
int Tot; void ini_hash() //排序去重
{
for(int i =1; i <= n; i++)
t[i] = a[i];
sort(t+1,t+n+1);
m = unique(t+1,t+n+1)-t-1;
} int Hash(int x) //获得x在排序去重后的位置
{
return lower_bound(t+1,t+m+1,x) - t;
} int build(int l,int r)
{
int root = Tot++;
val[root] = 0;
if(l != r)
{
int mid = (l+r)>>1;
lson[root] = build(l,mid);
rson[root] = build(mid+1,r);
}
return root;
} //如果那里发生改变则兴建一个节点而非像平常修改那个节点的值
int update(int root,int pos,int va)
{
int newroot = Tot++;
int tmp = newroot;
val[newroot] = val[root] + va;
int l = 1,r = m;
while(l < r)
{
int mid = (l+r)>>1;
if(pos <= mid)
{
lson[newroot] = Tot++;
rson[newroot] = rson[root];
newroot = lson[newroot];
root = lson[root];
r = mid;
}
else
{
lson[newroot] = lson[root];
rson[newroot] = Tot++;
newroot = rson[newroot];
root = rson[root];
l = mid+1;
}
val[newroot] = val[root] + va;
}
return tmp;
} int query(int lt,int rt,int lca,int k)
{
int lca_rt = T[lca];
int pos = Hash(a[lca]);
int l = 1, r = m;
while(l < r)
{
int mid = (l+r)>>1;
int tmp = val[lson[lt]]+val[lson[rt]]-2*val[lson[lca_rt]]+(pos>=l&&pos<=mid);
if(tmp >= k)
{
lt = lson[lt];
rt = lson[rt];
lca_rt = lson[lca_rt];
r = mid;
}
else
{
k -= tmp;
l = mid+1;
lt = rson[lt];
rt = rson[rt];
lca_rt = rson[lca_rt];
}
}
return l;
} int rmq[maxn*2]; //表示深度
struct ST
{
int mm[maxn*2];
int dp[maxn*2][20];
void ini(int n)
{
mm[0] = -1;
for(int i = 1; i <= n; i++)
{
mm[i] = ((i&(i-1)) == 0)?mm[i-1]+1:mm[i-1];
dp[i][0] = i;
}
for(int j = 1; j <= mm[n]; j++)
for(int i = 1; i + (1<<j) - 1 <= n; i++)
dp[i][j] = rmq[dp[i][j-1]] < rmq[dp[i+(1<<(j-1))][j-1]]?
dp[i][j-1]:dp[i+(1<<(j-1))][j-1];
}
int query(int a,int b)
{
if(a > b)swap(a,b);
int k = mm[b-a+1];
return rmq[dp[a][k]] <= rmq[dp[b-(1<<k)+1][k]]?
dp[a][k]:dp[b-(1<<k)+1][k];
}
}; struct E
{
int to,next;
} edge[maxn*2];
int tot,head[maxn];
int F[maxn*2];
int P[maxn];
int cnt;
//F表示dfs的序列
//P[i]表示i第一次出现的位置 ST st;
void init() //初始化
{
Tot = tot = 0;
memset(head,-1,sizeof(head));
} void dfs(int u,int pre,int dep)
{
F[++cnt] = u;
rmq[cnt] = dep;
P[u] = cnt;
for(int i = head[u]; i != -1; i = edge[i].next)
{
int v = edge[i].to;
if(v == pre)continue;
dfs(v,u,dep+1);
F[++cnt] = u;
rmq[cnt] = dep;
}
} void ini_lca(int root,int num)
{
cnt = 0;
dfs(root,root,0);
st.ini(2*num-1);
} void addedge(int u,int v)
{
edge[tot].to = v;
edge[tot].next = head[u];
head[u] = tot++;
} int query_lca(int u,int v)
{
return F[st.query(P[u],P[v])];
} void dfs_build(int u,int pre)
{
int pos = Hash(a[u]);
T[u] = update(T[pre],pos,1);
for(int i = head[u]; i != -1; i = edge[i].next)
{
int v = edge[i].to;
if(v == pre) continue;
dfs_build(v,u);
}
} int main()
{
int q;
while(scanf("%d%d",&n,&q) == 2)
{
for(int i = 1; i <= n; i++)
scanf("%d",&a[i]);
ini_hash();
init();
int u,v,k;
for(int i = 1; i < n; i++)
{ scanf("%d%d",&u,&v);
addedge(u,v);
addedge(v,u);
}
ini_lca(1,n);
T[n+1] = build(1,m);
dfs_build(1,n+1);
while(q--)
{
scanf("%d%d%d",&u,&v,&k);
printf("%d\n",t[query(T[u],T[v],query_lca(u,v),k)]);
}
}
return 0;
}

  

SPOJ COT(树上的点权第k大)的更多相关文章

  1. LCA+主席树 (求树上路径点权第k大)

      SPOJ 10628. Count on a tree (树上第k大,LCA+主席树) 10628. Count on a tree Problem code: COT You are given ...

  2. Count on a tree(SPOJ COT + 树上第k大 + 主席树 + LCA)

    题目链接:https://www.spoj.com/problems/COT/en/ 题目: 题意: 给你一棵有n个节点的树,求节点u到节点v这条链上的第k大. 思路: 我们首先用dfs进行建题目给的 ...

  3. SPOJ Lexicographical Substring Search 求字典序第k大子串 后缀自动机

    题目传送门 思路:按字典序,小的字符优先选取.对于一个字符,如果以这个字符开头的子串大于等于k个,那说明这个字符是应该选的,并且选完之后,可能还要继续选.如果以这个字符开头的子串小于k个,说明这个字符 ...

  4. 【学术篇】SPOJ COT 树上主席树

    这是学完主席树去写的第二道题_(:з」∠)_ 之前用树上莫队水过了COT2... 其实COT也可以用树上莫队水过去不过好像复杂度要带个log还是怎么样可能会被卡常数.. 那就orz主席吧.... 写了 ...

  5. 计蒜客 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 ...

  6. 主席树——树链上第k大spoj COT

    首先要求第k大就想到用主席树来处理 但是不能直接用树链剖分的dfs序来维护,因为一条链对应的dfs下标可能是断开的几段,无法用权值线段树来维护 那么久维护每个点到根节点的全值线段树,结点u的权值线段树 ...

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

  8. bzoj 3784: 树上的路径 堆维护第k大

    3784: 树上的路径 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 88  Solved: 27[Submit][Status][Discuss] ...

  9. HDU 4729 An Easy Problem for Elfness (主席树,树上第K大)

    转载请注明出处,谢谢http://blog.csdn.net/ACM_cxlove?viewmode=contents    by---cxlove 题意:给出一个带边权的图.对于每一个询问(S , ...

随机推荐

  1. java unicode和字符串间的转换

    package ykxw.web.jyf; /** * Created by jyf on 2017/5/16. */ public class unicode { public static voi ...

  2. java 1.7新特性

    try( ... ){ ... } catch(xxx e){ ... } java1.7特性,叫做try-with-resource,实现了AutoCloseable接口的实例可以放在try(... ...

  3. JAVA_SE基础——3.Java程序的开发流程

    上一篇,写的是JAVA的环境变量的配置,今天我抽空写篇Java程序的开发流程,下面的教程是我结合书本和毕向东老师的视频写下的心的~ 在没有真正写Java程序前,首先需要了解Java程序的开发过程. S ...

  4. MSIL实用指南-生成接口

    本篇讲解怎么样生成接口,即interface. 一.创建类型创建一个接口类型依旧用ModuleBuilder的DefineType方法,但是它的第二个参数必须要有TypeAttributes.Inte ...

  5. Windows中添加自己的程序到开机启动中(添加服务,添加注册表)

    在系统启动的时候启动自己想要启动的程序: 方法一:利用开机启动文件夹 将exe文件或exe文件的快捷方式复制到(启动)文件夹下 以win7为例:开始→所有程序→启动→鼠标右键打开 方法二:添加系统服务 ...

  6. js的构造函数共用事例

    在使用构造函数去实现一种功能时,我们有时候往往需要实现这个功能,会因此产生多个堆内对象.这样就会造成堆内存滥用.占用不该占用的空间.为此我们可以利用函数把共用的内容封装起来.放便我们的使用.很多东西其 ...

  7. Linq 大合集

    static void Main(string[] args) { string[] words = { "zero", "one", "two&qu ...

  8. node express将请求重定向为https

    项目开发时,由于服务器只接受https请求(运维说了算...),所以在生产环境时,要把所有http请求全都重定向为https,具体操作是在app.js文件里加入以下代码: var express = ...

  9. Python内置函数(64)——classmethod

    英文文档: classmethod(function) Return a class method for function. A class method receives the class as ...

  10. 说说Java代理模式

    代理实现可以分为静态代理和动态代理. 静态代理 静态代理模式其实很常见,比如买火车票这件小事:黄牛相当于是火车站的代理,我们可以通过黄牛买票,但只能去火车站进行改签和退票.在代码实现中相当于为一个委托 ...