SPOJ-COT-Count on a tree(树上路径第K小,可持久化线段树)
题意:
求树上A,B两点路径上第K小的数
分析:
同样是可持久化线段树,只是这一次我们用它来维护树上的信息。
我们之前已经知道,可持久化线段树实际上是维护的一个前缀和,而前缀和不一定要出现在一个线性表上。
比如说我们从一棵树的根节点进行DFS,得到根节点到各节点的距离dist[x]——这是一个根-x路径上点与根节点距离的前缀和。
利用这个前缀和,我们可以解决一些树上任意路径的问题,比如在线询问[a,b]点对的距离——答案自然是dist[a]+dist[b]-2*dist[lca(a,b)]。
同理,我们可以利用可持久化线段树来解决树上任意路径的问题。
DFS遍历整棵树,然后在每个节点上建立一棵线段树,某一棵线段树的“前一版本”是位于该节点父亲节点fa的线段树。
利用与之前类似的方法插入点权(排序离散)。那么对于询问[a,b],答案就是root[a]+root[b]-root[lca(a,b)]-root[fa[lca(a,b)]]上的第k大。
// File Name: cot.cpp
// Author: Zlbing
// Created Time: 2013年10月09日 星期三 19时24分55秒 #include<iostream>
#include<string>
#include<algorithm>
#include<cstdlib>
#include<cstdio>
#include<set>
#include<map>
#include<vector>
#include<cstring>
#include<stack>
#include<cmath>
#include<queue>
using namespace std;
#define CL(x,v); memset(x,v,sizeof(x));
#define INF 0x3f3f3f3f
#define LL long long
#define REP(i,r,n) for(int i=r;i<=n;i++)
#define RREP(i,n,r) for(int i=n;i>=r;i--)
const int MAXN=1e5+;
const int POW=;
int num[MAXN],hash[MAXN];
int ls[MAXN*],rs[MAXN*];
int sum[MAXN*];
int root[MAXN];
vector<int> G[MAXN];
int d[MAXN];
int p[MAXN][POW];
int tot;
int f[MAXN];
void build(int l,int r,int& rt)
{
rt=++tot;
sum[rt]=;
if(l>=r)return;
int m=(l+r)>>;
build(l,m,ls[rt]);
build(m+,r,rs[rt]);
}
void update(int last,int p,int l,int r,int &rt)
{
rt=++tot;
ls[rt]=ls[last];
rs[rt]=rs[last];
sum[rt]=sum[last]+;
if(l>=r)return ;
int m=(l+r)>>;
if(p<=m)update(ls[last],p,l,m,ls[rt]);
else update(rs[last],p,m+,r,rs[rt]);
}
int query(int left_rt,int right_rt,int lca_rt,int lca_frt,int l,int r,int k)
{
if(l>=r)return l;
int m=(l+r)>>;
int cnt=sum[ls[right_rt]]+sum[ls[left_rt]]-sum[ls[lca_rt]]-sum[ls[lca_frt]];
if(k<=cnt)
return query(ls[left_rt],ls[right_rt],ls[lca_rt],ls[lca_frt],l,m,k);
else
return query(rs[left_rt],rs[right_rt],rs[lca_rt],rs[lca_frt],m+,r,k-cnt);
}
void dfs(int u,int fa,int cnt)
{
f[u]=fa;
d[u]=d[fa]+;
p[u][]=fa;
for(int i=;i<POW;i++)p[u][i]=p[p[u][i-]][i-]; update(root[fa],num[u],,cnt,root[u]);
for(int i=;i<(int)G[u].size();i++)
{
int v=G[u][i];
if(v==fa)continue;
dfs(v,u,cnt);
}
}
int lca(int a,int b)
{
if(d[a]>d[b])a^=b,b^=a,a^=b;
if(d[a]<d[b])
{
int del=d[b]-d[a];
for(int i=;i<POW;i++)
if(del&(<<i))b=p[b][i];
}
if(a!=b)
{
for(int i=POW-;i>=;i--)
{
if(p[a][i]!=p[b][i])
{
a=p[a][i],b=p[b][i];
}
}
a=p[a][],b=p[b][];
}
return a;
}
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m))
{
REP(i,,n)
{
G[i].clear();
}
CL(d,);
CL(p,);
CL(f,);
REP(i,,n)
{
scanf("%d",&num[i]);
hash[i]=num[i];
}
tot=;
sort(hash+,hash++n);
int cnt=unique(hash+,hash+n+)-hash-;
REP(i,,n)
{
num[i]=lower_bound(hash+,hash+cnt+,num[i])-hash;
}
int a,b,c;
REP(i,,n-)
{
scanf("%d%d",&a,&b);
G[a].push_back(b);
G[b].push_back(a);
}
build(,cnt,root[]);
dfs(,,cnt);
REP(i,,m)
{
scanf("%d%d%d",&a,&b,&c);
int t=lca(a,b);
int id=query(root[a],root[b],root[t],root[f[t]],,cnt,c);
printf("%d\n",hash[id]);
}
}
return ;
}
SPOJ-COT-Count on a tree(树上路径第K小,可持久化线段树)的更多相关文章
- Count on a tree(树上路径第K小)
题目链接:https://www.spoj.com/problems/COT/en/ 题意:求树上A,B两点路径上第K小的数 思路:主席树实际上是维护的一个前缀和,而前缀和不一定要出现在一个线性表上. ...
- spoj COT - Count on a tree (树上第K小 LCA+主席树)
链接: https://www.spoj.com/problems/COT/en/ 思路: 首先看到求两点之前的第k小很容易想到用主席树去写,但是主席树处理的是线性结构,而这道题要求的是树形结构,我们 ...
- Count on a tree 树上区间第K小
Count on a tree 题意:求路径 u到v上的 第k小的权重. 题解:先DFS建数, 然后对于每个节点往上跑出一颗主席树, 然后每次更新. 查询的时候, u, v, k, 找到 z = l ...
- SPOJ COT Count on a tree(树上主席树 + LCA 求点第k小)题解
题意:n个点的树,每个点有权值,问你u~v路径第k小的点的权值是? 思路: 树上主席树就是每个点建一棵权值线段树,具体看JQ博客,LCA用倍增logn求出,具体原理看这里 树上主席树我每个点的存的是点 ...
- 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 ...
- SPOJ 10628 Count on a tree(Tarjan离线 | RMQ-ST在线求LCA+主席树求树上第K小)
COT - Count on a tree #tree You are given a tree with N nodes.The tree nodes are numbered from 1 to ...
- 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 ...
- 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 ...
- spoj COT - Count on a tree(主席树 +lca,树上第K大)
您将获得一个包含N个节点的树.树节点的编号从1到Ñ.每个节点都有一个整数权重. 我们会要求您执行以下操作: uvk:询问从节点u到节点v的路径上的第k个最小权重 输入 在第一行中有两个整数Ñ和中号.( ...
随机推荐
- SQL Server中建立外键的方法
在SQL中建立外键约束,可以级联查询表中的数据,在C#代码生成器中,也能根据外键关系生成相应的外键表数据模型.外键也可防止删除有外键关系的记录,一定程度上保护了数据的安全性. 步骤: 1.要建立外键关 ...
- 程序员带你学习安卓开发,十天快速入-对比C#学习java语法
关注今日头条-做全栈攻城狮,学代码也要读书,爱全栈,更爱生活.提供程序员技术及生活指导干货. 如果你真想学习,请评论学过的每篇文章,记录学习的痕迹. 请把所有教程文章中所提及的代码,最少敲写三遍,达到 ...
- [原创]ie6,7中td和img之间有间隙
情形描述 开发工具:VS2010: 浏览器版本:IE6以上,火狐,谷歌: 页面布局设计:Table+Img布局: 项目预览问题:火狐,谷歌,IE8以上未出现问题,IE6,IE7图片之间有间隙. 分析原 ...
- [Mime] MimeReader--读取Mime的帮助类 (转载)
点击下载 MimeReader.rar 这个类是关于MimeReader的帮助类看下面代码吧 /// <summary> /// 类说明:Assistant /// 编 码 人:苏飞 // ...
- Animating Layout Changes(展开收起)
原文地址:https://developer.android.com/training/animation/layout.html#add (1)设置布局文件: <LinearLayout an ...
- C# 跨线程调用问题
纠结了好久,终于知道了winform和WPF的UI的跨线程调用的解决方法: winform下如果为了省事,可以直接禁用跨线程检查: Control.CheckForIllegalCrossThread ...
- iOS支付总结
内容大纲: 一.常见的支付方案简介 二.第三方支付SDK 三.苹果官方支付方案 四.Web支付方案 正文: 一.常见的支付方案简介 在微信支付中 微信支付的网址是: https://pay.weixi ...
- 5 DML语言
body { font-family: "Microsoft YaHei UI","Microsoft YaHei",SimSun,"Segoe UI ...
- React学习笔记(二) 组件状态
组件的状态(this.state): 组件免不了要与用户互动,React 的一大创新,就是将组件看成是一个状态机,一开始有一个初始状态,然后用户互动,导致状态变化,从而触发重新渲染 UI getIni ...
- PC110302/UVA10010
下周开始就省选了,ACM的日子在今年内应该就会结束了,大三了,最后一次机会了,小小感伤一下-- 今天广州下大雨,心情怪怪的,感觉码不出质量高的,又很久没做过PC了,就刷刷水题吧. 老实说Program ...