Count on a tree SPOJ 10628 主席树+LCA(树链剖分实现)(两种存图方式)

题外话,这是我第40篇随笔,纪念一下。<( ̄︶ ̄)↗[GO!]

题意

是说有棵树,每个节点上都有一个值,然后让你求从一个节点到另一个节点的最短路上第k小的值是多少。

解题思路

看到这个题一想以为是树链剖分+主席树,后来写着写着发现不对,因为树链剖分我们分成了一小段一小段,这些小段不能合并起来求第k小,所以这个想法不对。奈何不会做,查了查题解,需要用LCA(最近公共祖先),然后根据主席树具有区间加减的性质,我们查询一段区间的状态可以从LCA的角度去看问题,找到LCA(x, y)然后,我们只要一个LCA节点,然后求出区间X到根节点,以及Y到根节点的关系式来推这个关系,但是千万不要去减两倍LCA的关系,因为那样就会少掉一个节点了,于是,就dfs()往下建树,就是寻找到最后的答案。
\[ t[t[x].l].sum + t[t[y].l].sum - t[t[lca].l].sum - t[t[gra].l].sum \]
注意:这里我求LCA的方法是用的树链剖分的方法,求LCA的方法有很多,但是我就会这一种?

如果没有学过树链剖分,我这里有一些学习资料推荐,点我。

如果没有学过主席树,别急,我这也有好的视频和博客推荐,点我。

上面两个都是我学习过程中遇到的好的博客文章的收集,节省再次查找的时间

代码实现(图用vector存版,用链式向前星版)

//vector版,方便但是稍微慢一些
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn=1e5+100;
struct node{int l, r, sum;
}t[maxn*40];
vector<int> g[maxn];
vector<int> v;
int tot, root[maxn], w[maxn];int dep[maxn], f[maxn], size[maxn], son[maxn];
int top[maxn];
int n, m, nn; //nn是实际去重后的个数
int read() //快读函数,这里已经实验过了,用和不用都行,用了会快一些。
{int f=1,x=0;char ss=getchar();while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}return f*x;
}
int getid(int x) //离散化之后求坐标
{return lower_bound(v.begin() , v.end() , x)- v.begin() +1;
}
void dfs1(int u, int fa, int depth)
{size[u]=1;dep[u]=depth;f[u]=fa;int len=g[u].size();for(int i=0; i<len; i++){int v=g[u][i];if(v==fa) continue;dfs1(v, u, depth+1);size[u]+=size[v];if(size[v] > size[son[u]])son[u]=v;}
}
void dfs2(int u, int tp)
{top[u]=tp;if(!son[u])return ;dfs2(son[u], tp);int len=g[u].size();for(int i=0; i<len; i++){int v=g[u][i];if(v==son[u] || v==f[u])continue;dfs2(v, v);}
}
int lca(int x,int y)
{int fx=top[x], fy=top[y];while(fx!=fy){if(dep[fx] < dep[fy]) {swap(x, y);swap(fx, fy);}x=f[fx]; //这里右边是fx,千万别写错了,我就是这犯了错,wa了几十下。。。fx=top[x];}return dep[x] < dep[y] ? x : y ;
}
void update(int l, int r, int pre, int &now, int pos)
{t[++tot]=t[pre];t[tot].sum++;now=tot;if(l==r) return ;int mid=(l+r)>>1;if(pos<=mid)update(l, mid, t[pre].l, t[now].l, pos);else update(mid+1, r, t[pre].r, t[now].r, pos);
}
int query(int l, int r, int x, int y, int lca, int gra, int k)
{if(l==r)return l;int mid=(l+r)>>1;int sum=t[t[x].l].sum + t[t[y].l].sum - t[t[lca].l].sum - t[t[gra].l].sum ;if(k<=sum)return query(l, mid, t[x].l, t[y].l, t[lca].l, t[gra].l, k);else return query(mid+1, r, t[x].r, t[y].r, t[lca].r, t[gra].r, k-sum);
}
void dfs(int u)
{int pos=getid(w[u]);update(1, nn, root[f[u]], root[u], pos);int len=g[u].size();for(int i=0; i<len; i++){int v=g[u][i];if(v==f[u])continue;dfs(v);}
}
int main()
{scanf("%d%d", &n, &m); for(int i=1; i<=n; i++){w[i]=read();v.push_back(w[i]);}sort(v.begin() , v.end() );v.erase( unique( v.begin() , v.end() ), v.end());nn=v.size();int x, y;for(int i=1; i<n; i++){scanf("%d%d", &x, &y);g[x].push_back(y);g[y].push_back(x);}dfs1(1, 0, 1);dfs2(1, 1);dfs(1);int k, la;for(int i=1; i<=m; i++){scanf("%d%d%d", &x, &y, &k);la=lca(x, y);printf("%d\n", v[ query(1, nn, root[x], root[y], root[la], root[ f[la] ], k) -1 ] );}return 0;
}
// 链式向前星版存图
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<iostream>
using namespace std;
const int maxn=1e5+10000;
struct node{int l, r, sum;
}t[maxn*40];
int tot; //tot是主席树点的个数 struct edge{int to, next;
}e[maxn<<1];
int head[maxn], cnt; //cnt是边的个数 int root[maxn], w[maxn], id[maxn];int dep[maxn], f[maxn], size[maxn], son[maxn];
int top[maxn];
int n, m, nn;
inline int read()
{int f=1,x=0;char ss=getchar();while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}return f*x;
}
inline void add(int u, int v)
{e[++cnt].next=head[u];e[cnt].to=v;head[u]=cnt;
}int getid(int x)
{return (lower_bound(&id[1] , &id[nn+1] , x)-id);
}void update(int l, int r, int pre, int &now, int pos)
{t[++tot]=t[pre];t[tot].sum++;now=tot;if(l==r) return ;int mid=(l+r)>>1;if(pos<=mid)update(l, mid, t[pre].l, t[now].l, pos);elseupdate(mid+1, r, t[pre].r, t[now].r, pos);
}int query(int l, int r, int x, int y, int lca, int gra, int k)
{if(l==r)return l;int mid=(l+r)>>1;int sum=t[t[x].l].sum + t[t[y].l].sum - t[t[lca].l].sum - t[t[gra].l].sum ;if(k<=sum)return query(l, mid, t[x].l, t[y].l, t[lca].l, t[gra].l, k);elsereturn query(mid+1, r, t[x].r, t[y].r, t[lca].r, t[gra].r, k-sum);
}
void dfs1(int u, int fa, int depth)
{size[u]=1;dep[u]=depth;f[u]=fa;for(int i=head[u]; i; i=e[i].next){int v=e[i].to;if(v==fa)continue;dfs1(v, u, depth+1);size[u]+=size[v];if(size[v] > size[son[u]])son[u]=v;}
}
void dfs2(int u, int tp)
{top[u]=tp;if(!son[u])return ;dfs2(son[u], tp);for(int i=head[u]; i; i=e[i].next){int v=e[i].to;if(v==son[u] || v==f[u])continue;dfs2(v, v);}
}int lca(int x,int y)
{int fx=top[x], fy=top[y];while(fx!=fy){if(dep[fx] < dep[fy]){swap(x, y);swap(fx, fy);}x=f[fx];fx=top[x];}return dep[x] < dep[y] ? x : y ;
}
void dfs(int u)
{int pos=getid(w[u]);update(1, nn, root[f[u]], root[u], pos);for(int i=head[u]; i; i=e[i].next){int v=e[i].to;if(v==f[u])continue;dfs(v);}
}
int main()
{scanf("%d%d", &n, &m);for(int i=1; i<=n; i++){scanf("%d", &w[i]);id[i]=w[i];}sort(&id[1], &id[n+1] );nn = (unique( &id[1], &id[n+1])-id-1) ;int x, y;for(int i=1; i<n; i++){scanf("%d%d", &x, &y);add(x, y);add(y, x);}dfs1(1, 0, 1);dfs2(1, 1);dfs(1);int k, la;for(int i=1; i<=m; i++){scanf("%d%d%d", &x, &y, &k);la=lca(x, y);printf("%d\n", id[ query(1, nn, root[x], root[y], root[la], root[ f[la] ], k) ] );}return 0;
}

转载于:https://www.cnblogs.com/alking1001/p/11432494.html

Count on a tree SPOJ 10628 主席树+LCA(树链剖分实现)(两种存图方式)相关推荐

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

  2. BZOJ2588 Count on a tree 【树上主席树】

    2588: Spoj 10628. Count on a tree Time Limit: 12 Sec  Memory Limit: 128 MB Submit: 7577  Solved: 185 ...

  3. 蒟蒻浅谈树链剖分之一——两个dfs操作

    树链剖分,顾名思义就是将树形的结构剖分成链,我们以此便于在链上操作 首先我们需要明白在树链剖分中的一些概念 重儿子:某节点所有儿子中子树最多的儿子 重链:有重儿子构成的链 dfs序:按重儿子优先遍历时 ...

  4. HDU - 6393 Traffic Network in Numazu(线段树+LCA+树链剖分+并查集)

    题目链接:点击查看 题目大意:给出一个由n个点和n条边组成的图,每条边都有权值,题目保证图是连通的,然后给出m个询问,每次询问分为两种形式: 0 x y:将第x条边的权值修改为y 1 x y:查询x- ...

  5. datawhale 10月学习——树模型与集成学习:两种并行集成的树模型

    前情回顾 决策树 CART树的实现 集成模式 结论速递 本次学习了两种并行集成的树模型,随机森林和孤立森林,并进行了相应的代码实践.其中对孤立森林的学习比较简略,有待后续补充. 这里写自定义目录标题 ...

  6. Count on a tree SPOJ - COT

    题意:求树上A,B两点路径上第K小的数 AT #include<cstdio> #include<iostream> #include<algorithm> #in ...

  7. CF613D-Kingdom and its Cities【虚树,LCA,树链剖分,贪心】

    正题 题目链接:https://www.luogu.org/problem/CF613D 题目大意 一棵树,每次询问kkk个点,删除mmm个点要这些点两两不连通,求mmm的最小值. 解题思路 我们可以 ...

  8. 主席树 || 可持久化线段树 || LCA || BZOJ 2588: Spoj 10628. Count on a tree || Luogu P2633 Count on a tree...

    题面: Count on a tree 题解: 主席树维护每个节点到根节点的权值出现次数,大体和主席树典型做法差不多,对于询问(X,Y),答案要计算ans(X)+ans(Y)-ans(LCA(X,Y) ...

  9. 树链剖分入门+HYSBZ - 1036树的统计Count

    今天学习了树链剖分,记录一下. [题目背景] HYSBZ - 1036树的统计Count [题目分析] 题目要求求任意结点之间路径的和以及路径上最大的结点,还有可能修改.如果正常做可能会很复杂(我也不 ...

  10. 洛谷P4482 [BJWC2018]Border 的四种求法 字符串,SAM,线段树合并,线段树,树链剖分,DSU on Tree...

    原文链接https://www.cnblogs.com/zhouzhendong/p/LuoguP4482.html 题意 给定一个字符串 S,有 q 次询问,每次给定两个数 L,R ,求 S[L.. ...

最新文章

  1. SAP SD销售业务中客户投诉退货的处理方案
  2. 《数据库原理与应用》(第三版) 第8章 关系数据库理论 基础 习题参考答案
  3. 用GCD线程组与GCD信号量将异步线程转换为同步线程
  4. 主机测评软件_海外主机测评丨SugarHosts 美国虚拟主机测评
  5. 基于JAVA+SpringMVC+Mybatis+MYSQL的大学生毕业设计管理系统
  6. Java多线程基本概念
  7. android使用greedao踩坑日记
  8. java中线程的生命周期_Java中的线程生命周期– Java中的线程状态
  9. 20200519每日一句
  10. datagrid嵌套使用ajax,关于easyui datagrid多层嵌套动态合并列的问题
  11. 教务系统自动评教_「四川大学教务处本科登陆系统」四川大学本科教务系统 - 一键评教 - seo实验室...
  12. centos检测不到磁盘_linux – Centos 7服务器看不到磁盘阵列磁盘
  13. DDNS - 动态DNS
  14. Spring In Action 4 学习笔记(一)Spring概览
  15. 恭喜猛龙获得NBA总冠军
  16. sklearn基础篇(三)-- 鸢尾花(iris)数据集分析和分类
  17. A7139射频模块wor配置解析
  18. 思杰虚拟服务器退出管理主机,详解Citrix思杰XenServer虚拟化(7)
  19. fastethernet 0/0
  20. Comprehensive survey of computational ECG analysis: Databases,methods and applications

热门文章

  1. JMM同步规范和Volatile重点概要
  2. MySQL中exists和in的区别
  3. Spring Data JPA持久层中的一对一和一对多
  4. Data Lake Analytics,大数据的ETL神器! 1
  5. android DVM
  6. [WPF] 托盘菜单的基本功能实现
  7. git 非空目录添加远程仓库地址
  8. c语言第11章ppt,C语言程序设计第11章xg.ppt
  9. Android常用组件
  10. CF1042F Leaf Sets