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}$ ...
随机推荐
- IDEA中解决 git pull 冲突
0.事先准备.1)把远程仓库的README.md内容改写为bbb(原先为aaa). 2)本地仓库的README.md内容改写为ccc(原先也为aaa). 以此来模仿代码冲突. 1.先commit ...
- ubuntu 安装企业级容器 docker harbor
安装docker harbor 企业级容器 环境说明: 操作系统: ubuntu16.04.5 LTS IP地址: 192.168.31.129 https://github.com/goh ...
- 1000行基本SQL
/* Windows服务 */ -- 启动MySQL net start mysql -- 创建Windows服务 sc create mysql binPath= mysqld_bin_path(注 ...
- oracle 实现mysql find_set_in函数
create or replace FUNCTION F_FIND_IN_SET(piv_str1 varchar2, piv_str2 varchar2, p_sep varchar2 := ',' ...
- logstash启动时找不到自定义的JAVA_HOME环境变量
logstash java 版本问题 配置logstash收集应用日志时出现报错,说是找不到JAVA_HOME环境变量,但是明明已经设置了 logstash要求java 1.8以上,查看生产环境: [ ...
- go & log
更多日志库 https://github.com/golang/glog github.com/astaxie/beego/logs ... 这里有一个讨论 Golang的log包哪个好用? 参考 G ...
- Maven下载清除jar包
maven jar包下载命令行方式 在STS中下载JAR包时经常卡住无法继续下载,这时可以用命令行方式进行下载.在终端中今入到该项目的根目录下,然后mvn clean;mvn install;等待下载 ...
- [七月挑选]IntelliJ IDEA常用设置
title: IntelliJ IDEA常用设置 设置idea的类注释快捷键 File -> Settings -> Live Templates 1.右边的 + -> Templa ...
- order by关键字优化
1.ORDER BY子句,尽量使用Index方式排序,避免使用FileSort方式排序 2.建表SQL CREATE TABLE tblA( id int primary key not null a ...
- Mongo--03 mongo副本集、备份与恢复
目录 一.mongo副本集配置 二.查看副本集状态 三.副本集权重调整 四.创建节点 五.仲裁节点 六.mongo备份与恢复 七.准备测试数据 一.mongo副本集配置 1.创建节点目录和数据目录 # ...