题目链接: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小)的更多相关文章

  1. Count on a tree 树上区间第K小

    Count on a tree 题意:求路径 u到v上的 第k小的权重. 题解:先DFS建数, 然后对于每个节点往上跑出一颗主席树, 然后每次更新. 查询的时候, u, v, k, 找到  z = l ...

  2. SPOJ-COT-Count on a tree(树上路径第K小,可持久化线段树)

    题意: 求树上A,B两点路径上第K小的数 分析: 同样是可持久化线段树,只是这一次我们用它来维护树上的信息. 我们之前已经知道,可持久化线段树实际上是维护的一个前缀和,而前缀和不一定要出现在一个线性表 ...

  3. Count on a tree 树上主席树

    Count on a tree 树上主席树 给\(n\)个树,每个点有点权,每次询问\(u,v\)路径上第\(k\)小点权,强制在线 求解区间静态第\(k\)小即用主席树. 树上主席树类似于区间上主席 ...

  4. POJ 1741 Tree 求树上路径小于k的点对个数)

                                                                                                 POJ 174 ...

  5. E - Count on a tree 树上第K小

    主席树的入门题目,这道题的题意其实就是说,给你一棵树,询问在两个节点之间的路径上的区间第K小 我们如何把树上问题转换为区间问题呢? 其实DFS就可以,我们按照DFS的顺序,对线段树进行建树,那么这个树 ...

  6. spoj COT - Count on a tree (树上第K小 LCA+主席树)

    链接: https://www.spoj.com/problems/COT/en/ 思路: 首先看到求两点之前的第k小很容易想到用主席树去写,但是主席树处理的是线性结构,而这道题要求的是树形结构,我们 ...

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

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

  9. Codeforces 739B Alyona and a tree(树上路径倍增及差分)

    题目链接 Alyona and a tree 比较考验我思维的一道好题. 首先,做一遍DFS预处理出$t[i][j]$和$d[i][j]$.$t[i][j]$表示从第$i$个节点到离他第$2^{j}$ ...

随机推荐

  1. Go语言入门篇-环境准备

    一.GO语言特点 静态类型:首先要明确变量类型,如上所示. 编译型:指GO语言要被编译成机器能识别机器代码. GO语言开源. 编程范式:支持“函数式”和“面向对象” GO语言原生的支持并发编程:即GO ...

  2. django groupby 用法

  3. 多线程18-QueueUserWorkItem

        ));         }         ;             ;             ));             ThreadPool.QueueUserWorkItem(A ...

  4. SpringMVC 的Model值传到JSP页面中,用EL表达试取不到值

    解决方案 在jsp文件头 <%@ page isELIgnored="false" %>

  5. Java——HashMap使用Demo

    package map; import java.util.Collection; import java.util.HashMap; import java.util.Set; public cla ...

  6. 卸载yum-mysql

    注意事项:1. 卸载yum MYSQLsystemctl status mysqlsystemctl stop mysqlsystemctl disable mysqld rpm -qa | grep ...

  7. spark性能调优03-shuffle调优

    1.开启map端输出文件的合并机制 1.1 为什么要开启map端输出文件的合并机制 默认情况下,map端的每个task会为reduce端的每个task生成一个输出文件,reduce段的每个task拉取 ...

  8. 工作笔记之20170223:①关于Html5的placeholder属性,②以及input的outline:none的样式问题

    关于这边几个样式问题,重点有这么几个: (1)placeholder="请输入密码" (2) color:#BEB6B6; border:0px; border-bottom:1p ...

  9. spark 在启动的时候出现JAVA_HOME not set

    解决方法:在sbin目录下的spark-config.sh 中添加对应的jdk 路径,然后使用scp -r 命令复制到各个worker节点

  10. 常用css相关笔记

    最后一个css不加样式 .nav-sort li:not(:last-child) { border-bottom:#3e3e3e 1px solid; } 垂直居中 vertical-align: ...