SPOJ COT(树上的点权第k大)
| Time Limit: 129MS | Memory Limit: 1572864KB | 64bit IO Format: %lld & %llu |
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
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
7
题意:求树上的边[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大)的更多相关文章
- LCA+主席树 (求树上路径点权第k大)
SPOJ 10628. Count on a tree (树上第k大,LCA+主席树) 10628. Count on a tree Problem code: COT You are given ...
- Count on a tree(SPOJ COT + 树上第k大 + 主席树 + LCA)
题目链接:https://www.spoj.com/problems/COT/en/ 题目: 题意: 给你一棵有n个节点的树,求节点u到节点v这条链上的第k大. 思路: 我们首先用dfs进行建题目给的 ...
- SPOJ Lexicographical Substring Search 求字典序第k大子串 后缀自动机
题目传送门 思路:按字典序,小的字符优先选取.对于一个字符,如果以这个字符开头的子串大于等于k个,那说明这个字符是应该选的,并且选完之后,可能还要继续选.如果以这个字符开头的子串小于k个,说明这个字符 ...
- 【学术篇】SPOJ COT 树上主席树
这是学完主席树去写的第二道题_(:з」∠)_ 之前用树上莫队水过了COT2... 其实COT也可以用树上莫队水过去不过好像复杂度要带个log还是怎么样可能会被卡常数.. 那就orz主席吧.... 写了 ...
- 计蒜客 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 ...
- 主席树——树链上第k大spoj COT
首先要求第k大就想到用主席树来处理 但是不能直接用树链剖分的dfs序来维护,因为一条链对应的dfs下标可能是断开的几段,无法用权值线段树来维护 那么久维护每个点到根节点的全值线段树,结点u的权值线段树 ...
- 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 ...
- bzoj 3784: 树上的路径 堆维护第k大
3784: 树上的路径 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 88 Solved: 27[Submit][Status][Discuss] ...
- HDU 4729 An Easy Problem for Elfness (主席树,树上第K大)
转载请注明出处,谢谢http://blog.csdn.net/ACM_cxlove?viewmode=contents by---cxlove 题意:给出一个带边权的图.对于每一个询问(S , ...
随机推荐
- java unicode和字符串间的转换
package ykxw.web.jyf; /** * Created by jyf on 2017/5/16. */ public class unicode { public static voi ...
- java 1.7新特性
try( ... ){ ... } catch(xxx e){ ... } java1.7特性,叫做try-with-resource,实现了AutoCloseable接口的实例可以放在try(... ...
- JAVA_SE基础——3.Java程序的开发流程
上一篇,写的是JAVA的环境变量的配置,今天我抽空写篇Java程序的开发流程,下面的教程是我结合书本和毕向东老师的视频写下的心的~ 在没有真正写Java程序前,首先需要了解Java程序的开发过程. S ...
- MSIL实用指南-生成接口
本篇讲解怎么样生成接口,即interface. 一.创建类型创建一个接口类型依旧用ModuleBuilder的DefineType方法,但是它的第二个参数必须要有TypeAttributes.Inte ...
- Windows中添加自己的程序到开机启动中(添加服务,添加注册表)
在系统启动的时候启动自己想要启动的程序: 方法一:利用开机启动文件夹 将exe文件或exe文件的快捷方式复制到(启动)文件夹下 以win7为例:开始→所有程序→启动→鼠标右键打开 方法二:添加系统服务 ...
- js的构造函数共用事例
在使用构造函数去实现一种功能时,我们有时候往往需要实现这个功能,会因此产生多个堆内对象.这样就会造成堆内存滥用.占用不该占用的空间.为此我们可以利用函数把共用的内容封装起来.放便我们的使用.很多东西其 ...
- Linq 大合集
static void Main(string[] args) { string[] words = { "zero", "one", "two&qu ...
- node express将请求重定向为https
项目开发时,由于服务器只接受https请求(运维说了算...),所以在生产环境时,要把所有http请求全都重定向为https,具体操作是在app.js文件里加入以下代码: var express = ...
- Python内置函数(64)——classmethod
英文文档: classmethod(function) Return a class method for function. A class method receives the class as ...
- 说说Java代理模式
代理实现可以分为静态代理和动态代理. 静态代理 静态代理模式其实很常见,比如买火车票这件小事:黄牛相当于是火车站的代理,我们可以通过黄牛买票,但只能去火车站进行改签和退票.在代码实现中相当于为一个委托 ...