spoj COT - Count on a tree (树上第K小 LCA+主席树)
链接:
https://www.spoj.com/problems/COT/en/
思路:
首先看到求两点之前的第k小很容易想到用主席树去写,但是主席树处理的是线性结构,而这道题要求的是树形结构,我们可以用dfs跑出所有点离根的距离-dep[i](根为1,dep[1]也为1)在dfs的过程
中,我们对每一个节点建一棵线段树,那么【a,b】就是:root[a] + root[b] - root[lca(a,b)] - root[f[lca(a,b)]]; (因为a-b的路径上的权值还要算上lca(a,b)这个点,所以不是减2*root[lca(a,b)]);
实现代码:
- #include<bits/stdc++.h>
- using namespace std;
- #define ll long long
- #define lson l,m,rt<<1
- #define rson m+1,r,rt<<1|1
- #define mid int m = (l + r) >> 1
- const int M = 2e5 + ;
- int p[M][],dep[M],head[M],sum[M*],ls[M*],rs[M*],root[M*];
- int cnt1,n,idx,cnt,f[M];
- struct node {
- int to,next;
- }e[M];
- void add(int u,int v){
- e[++cnt1].to=v;e[cnt1].next=head[u];head[u]=cnt1;
- e[++cnt1].to=u;e[cnt1].next=head[v];head[v]=cnt1;
- }
- int lca(int a,int b){
- if(dep[a] > dep[b]) swap(a,b);
- int h = dep[b] - dep[a]; //h为高度差
- for(int i = ;(<<i)<=h;i++){ //(1<<i)&f找到h化为2进制后1的位置,移动到相应的位置
- if((<<i)&h) b = p[b][i];
- //比如h = 5(101),先移动2^0祖先,然后再移动2^2祖先
- }
- //cout<<a<<" "<<b<<endl;
- if(a!=b){
- for(int i = ;i >= ;i --){
- if(p[a][i]!=p[b][i]){ //从最大祖先开始,判断a,b祖先,是否相同
- a = p[a][i]; b = p[b][i]; //如不相同,a,b,同时向上移动2^j
- }
- }
- a = p[a][]; //这时a的father就是LCA
- }
- return a;
- }
- void build(int l,int r,int &rt){
- rt = ++idx;
- sum[rt] = ;
- if(l == r) return;
- mid;
- build(l,m,ls[rt]);
- build(m+,r,rs[rt]);
- }
- void update(int p,int l,int r,int old,int &rt){
- rt = ++idx;
- ls[rt] = ls[old]; rs[rt] = rs[old]; sum[rt] = sum[old] + ;
- if(l == r) return ;
- mid;
- if(p <= m) update(p,l,m,ls[old],ls[rt]);
- else update(p,m+,r,rs[old],rs[rt]);
- }
- int query(int a,int b,int lc,int cl,int l,int r,int k){
- if(l == r) return l;
- mid;
- int cnt = sum[ls[a]] + sum[ls[b]] - sum[ls[lc]] - sum[ls[cl]];
- if(k <= cnt)
- return query(ls[a],ls[b],ls[lc],ls[cl],l,m,k);
- else
- return query(rs[a],rs[b],rs[lc],rs[cl],m+,r,k-cnt);
- }
- int a[M],b[M];
- void dfs(int u,int fa){
- f[u] = fa;
- dep[u] = dep[fa] + ;
- p[u][] = fa;
- for(int i = ;i < ;i ++) p[u][i] = p[p[u][i-]][i-];
- update(a[u],,cnt,root[fa],root[u]);
- for(int i = head[u];i!=-;i = e[i].next){
- int v = e[i].to;
- if(v == fa) continue;
- dfs(v,u);
- }
- }
- int main()
- {
- int m;
- while(scanf("%d%d",&n,&m)!=EOF){
- cnt1 = ;
- memset(head,-,sizeof(head));
- memset(dep,,sizeof(dep));
- memset(p,,sizeof(p));
- memset(f,,sizeof(f));
- for(int i = ; i <= n;i ++){
- scanf("%d",&a[i]);
- b[i] = a[i];
- }
- idx = ;
- int l,r,c;
- sort(b+,b+n+);
- cnt = unique(b+,b++n)-b-;
- for(int i = ;i <= n;i ++)
- a[i] = lower_bound(b+,b+cnt+,a[i]) - b;
- for(int i = ;i <= n-;i ++){
- scanf("%d%d",&l,&r);
- add(l,r);
- }
- build(,cnt,root[]);
- dfs(,);
- for(int i = ;i <= m;i ++){
- scanf("%d%d%d",&l,&r,&c);
- int lc = lca(l,r);
- int id = query(root[l],root[r],root[lc],root[f[lc]],,cnt,c);
- printf("%d\n",b[id]);
- }
- }
- return ;
- }
spoj COT - Count on a tree (树上第K小 LCA+主席树)的更多相关文章
- E - Count on a tree 树上第K小
主席树的入门题目,这道题的题意其实就是说,给你一棵树,询问在两个节点之间的路径上的区间第K小 我们如何把树上问题转换为区间问题呢? 其实DFS就可以,我们按照DFS的顺序,对线段树进行建树,那么这个树 ...
- 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 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个点的树,每个点有权值,问你u~v路径第k小的点的权值是? 思路: 树上主席树就是每个点建一棵权值线段树,具体看JQ博客,LCA用倍增logn求出,具体原理看这里 树上主席树我每个点的存的是点 ...
- spoj cot: Count on a tree 主席树
10628. Count on a tree Problem code: COT You are given a tree with N nodes.The tree nodes are number ...
- SPOJ 10628. SPOJ COT Count on a tree 可持久化线段树
这题是裸的主席树,每个节点建一棵主席树,再加个lca就可以了. 历尽艰辛,终于A掉了这一题,这般艰辛也显示出了打代码的不熟练. 错误:1.lca倍增的时候i和j写反了,RE了5次,实在要吸取教训 2. ...
- spoj COT - Count on a tree(主席树 +lca,树上第K大)
您将获得一个包含N个节点的树.树节点的编号从1到Ñ.每个节点都有一个整数权重. 我们会要求您执行以下操作: uvk:询问从节点u到节点v的路径上的第k个最小权重 输入 在第一行中有两个整数Ñ和中号.( ...
- SPOJ 10628 COT - Count on a tree(在树上建立主席树)(LCA)
COT - Count on a tree #tree You are given a tree with N nodes.The tree nodes are numbered from 1 to ...
随机推荐
- 重度使用示波器进行优化分析——一个DSDA项目回顾
这是若干年前一个项目,最近有时间整理一下.回忆起来,印象最深刻的就是重度使用示波器辅助分析,进行优化. 项目背景是在原有项目3G+项目基础上,增加一颗2G+ Modem,使支持DSDA功能. 在介绍D ...
- [04] 高级映射 association和collection
之前我们提到的映射,都是简单的字段和对象属性一对一,假设对象的属性也是一个对象,即涉及到两个表的关联,此时应该如何进行映射处理? 先看两张表,author 和 book: 业务上对应关系为,一个 ...
- 请允许我转载一篇关于套接字的博客:Socket
这一篇文章,我将图文并茂地介绍Socket编程的基础知识,我相信,如果你按照步骤做完实验,一定可以对Socket编程有更好地理解. 本文源代码,可以通过这里下载 http://files.cnblog ...
- 51nod 抽卡大赛
抽卡大赛 链接 分析: $O(n^4)$的做法比较好想,枚举第i个人选第j个,然后背包一下,求出有k个比他大的概率. 优化: 第i个人,选择一张卡片,第j个人选的卡片大于第i个人的概率是$p_j$,那 ...
- java基础(个人学习笔记) A
1. 声明long类型的变量 需要在数值的末尾+l/L.(不加L的话,貌似默认就是int型了.当给long赋值一个超过int范围的值的时候,会出问题.) 2. package java_ ...
- Vue2.0 搭配 axios
1.安装axios $ npm install axios 2.Demo (1)Get // 为给定 ID 的 user 创建请求 axios.get('/user?ID=12345') .then( ...
- Authorize的Forms认证
页面请求步骤: 1.登录地址: http://localhost:4441/SysLogin/AdminLogin 2.登陆成功地址:http://localhost:4441/Frame/MainF ...
- 树莓派 Raspberry Pi 更换国内源
http://www.shumeipaiba.com/wanpai/jiaocheng/16.html
- [Beta]M2事后分析
计划 你原计划的工作是否最后都做完了? 如果有没做完的,为什么? 答:没有,全部的功能没有实现.其中,界面还差两个,逻辑还差闹钟逻辑和群组逻辑,可以说这些东西是我们的核心功能之一,缺失了他们对我们整个 ...
- 《Linux内核设计与实现》第17章学习笔记
第17章.设备与模块 17.1设备类型 1.块设备(blkdev): 寻址以块为单位,通常支持重定位操作.通过称为“块设备节点”的特殊文件来访问. 2.字符设备(cdev): 不可寻址,仅提供数据的流 ...