Count on a tree(树上路径第K小)
题目链接:https://www.spoj.com/problems/COT/en/
题意:求树上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大。
#include<cstdio>
#include<cstring>
#include<queue>
#include<cmath>
#include<algorithm>
#include<map>
#include<vector>
#include<string>
#include<set>
#define ll long long
#define maxn 100007
using namespace std;
const int MAXN=1e5+;
const int POW=;
int num[MAXN],node[MAXN];
struct point
{
int l;
int r;
int sum;
}T[MAXN*];
int root[MAXN];
vector<int> G[MAXN];
int d[MAXN];
int p[MAXN][POW];
int tot;
int f[MAXN];
int n,m;
void build(int l,int r,int& rt)
{
rt=++tot;
T[rt].sum=;
if(l>=r)return;
int m=(l+r)>>;
build(l,m,T[rt].l);
build(m+,r,T[rt].r);
}
void update(int last,int p,int l,int r,int &rt)
{
rt=++tot;
T[rt].l=T[last].l;
T[rt].r=T[last].r;
T[rt].sum=T[last].sum+;
if(l>=r)return ;
int m=(l+r)>>;
if(p<=m)update(T[last].l,p,l,m,T[rt].l);
else update(T[last].r,p,m+,r,T[rt].r);
}
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=T[T[right_rt].l].sum+T[T[left_rt].l].sum-T[T[lca_rt].l].sum-T[T[lca_frt].l].sum;
if(k<=cnt)
return query(T[left_rt].l,T[right_rt].l,T[lca_rt].l,T[lca_frt].l,l,m,k);
else
return query(T[left_rt].r,T[right_rt].r,T[lca_rt].r,T[lca_frt].r,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;
}
void init()
{
for(int i=;i<=n;i++)
{
G[i].clear();
}
memset(d,,sizeof(d));
memset(p,,sizeof(p));
memset(f,,sizeof(f));
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
init();
for(int i=;i<=n;i++)
{
scanf("%d",&num[i]);
node[i]=num[i];
}
tot=;
sort(node+,node++n);
int cnt=unique(node+,node+n+)-node-;
for(int i=;i<=n;i++)
{
num[i]=lower_bound(node+,node+cnt+,num[i])-node;
}
int a,b,c;
for(int i=;i<=n-;i++)
{
scanf("%d%d",&a,&b);
G[a].push_back(b);
G[b].push_back(a);
}
build(,cnt,root[]);
dfs(,,cnt );
while(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",node[id]);
}
}
return ;
}
Count on a tree(树上路径第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(树上路径第K小,可持久化线段树)
题意: 求树上A,B两点路径上第K小的数 分析: 同样是可持久化线段树,只是这一次我们用它来维护树上的信息. 我们之前已经知道,可持久化线段树实际上是维护的一个前缀和,而前缀和不一定要出现在一个线性表 ...
- Count on a tree 树上主席树
Count on a tree 树上主席树 给\(n\)个树,每个点有点权,每次询问\(u,v\)路径上第\(k\)小点权,强制在线 求解区间静态第\(k\)小即用主席树. 树上主席树类似于区间上主席 ...
- POJ 1741 Tree 求树上路径小于k的点对个数)
POJ 174 ...
- E - Count on a tree 树上第K小
主席树的入门题目,这道题的题意其实就是说,给你一棵树,询问在两个节点之间的路径上的区间第K小 我们如何把树上问题转换为区间问题呢? 其实DFS就可以,我们按照DFS的顺序,对线段树进行建树,那么这个树 ...
- spoj COT - Count on a tree (树上第K小 LCA+主席树)
链接: https://www.spoj.com/problems/COT/en/ 思路: 首先看到求两点之前的第k小很容易想到用主席树去写,但是主席树处理的是线性结构,而这道题要求的是树形结构,我们 ...
- 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 ...
- Codeforces 739B Alyona and a tree(树上路径倍增及差分)
题目链接 Alyona and a tree 比较考验我思维的一道好题. 首先,做一遍DFS预处理出$t[i][j]$和$d[i][j]$.$t[i][j]$表示从第$i$个节点到离他第$2^{j}$ ...
随机推荐
- Environment Modules简单使用
Environment Modules简单使用 Environment Modules简介 Typically users initialize their environment when they ...
- 第六周总结&第四次实验报告
实验四 类的继承 一. 实验目的 (1) 掌握类的继承方法: (2) 变量的继承和覆盖,方法的继承.重载和覆盖实现: 二. 实验内容 三.实验过程 实验代码 package Shiyan4; publ ...
- 第八周课程总结&实验报告六
实验六 Java异常 实验目的 理解异常的基本概念: 掌握异常处理方法及熟悉常见异常的捕获方法. 实验要求 练习捕获异常.声明异常.抛出异常的方法.熟悉try和catch子句的使用. 掌握自定义异常类 ...
- Python模块logging
基本用法: import logging import sys # 获取logger实例,如果参数为空则返回root logger logger = logging.getLogger("A ...
- 洛谷 P1631 序列合并(优先队列)
传送门 解题思路 首先读入a.b数组后,sort一遍(从小到大),然后把a[1]+b[1],a[2]+b[1],a[3]+b[1]……a[n]+b[1]全部加入一个优先队列q(小根堆). 然后从一到n ...
- c++多线程并发学习笔记(1)
共享数据带来的问题:条件竞争 避免恶性条件竞争的方法: 1. 对数据结构采用某种保护机制,确保只有进行修改的线程才能看到修改时的中间状态.从其他访问线程的角度来看,修改不是已经完成了,就是还没开始. ...
- 小白学Python——用 百度AI 实现 OCR 文字识别
百度AI功能还是很强大的,百度AI开放平台真的是测试接口的天堂,免费接口很多,当然有量的限制,但个人使用是完全够用的,什么人脸识别.MQTT服务器.语音识别等等,应有尽有. 看看OCR识别免费的量 快 ...
- Vue切换页面时中断axios请求
一.概述 在Vue单页面开发过程中,遇到这样的情况,当我切换页面时,由于上一页面请求执行时间长,切换到该页面时,还未执行完,这时那个请求仍会继续执行直到请求结束,此时将会影响页面性能,并且可能对现在页 ...
- linux中几个简单的系统命令(还有一些其他杂项命令)
linux中几个简单的系统命令,其他命令接触到了在补充. 1.ps命令:(process status),提供对进程的一次性查看.以及执行ps命令时那个时刻的进程信息 格式:ps[参数] -e 此参数 ...
- IntelliJIdea初次接触
1.下载 在官网下载专业版https://www.jetbrains.com/idea/ 2.修改配置 bin目录下文件如下: 修改idea64.exe.vmoptions(64位执行文件idea64 ...