LCA+主席树 (求树上路径点权第k大)
SPOJ 10628. Count on a tree (树上第k大,LCA+主席树)
10628. Count on a treeProblem code: COT |
You are given a tree with N nodes.The tree nodes are numbered from 1 to N.Each node has an integer weight.
We will ask you to perform the following operation:
- u v k : ask for the kth minimum weight on the path from node u to node v
Input
In the first line there are two integers N and M.(N,M<=100000)
In the second line there are N integers.The ith integer denotes the weight of the ith node.
In the next N-1 lines,each line contains two integers u v,which describes an edge (u,v).
In the next M lines,each line contains three integers u v k,which means an operation asking for the kth minimum weight on the path from node u to node v.
Output
For each operation,print its result.
Example
- Input:
- 8 5
- 105 2 9 3 8 5 7 7
- 1 2
- 1 3
- 1 4
- 3 5
- 3 6
- 3 7
- 4 8
2 5 1
2 5 2
2 5 3
2 5 4
7 8 2
- Output:
- 2
8
9
105
7
在树上建立主席树。
然后求LCA
- #include <stdio.h>
- #include <string.h>
- #include <iostream>
- #include <algorithm>
- #include <vector>
- #include <queue>
- #include <set>
- #include <map>
- #include <string>
- #include <math.h>
- #include <stdlib.h>
- #include <time.h>
- using namespace std;
- //主席树部分 *****************8
- const int MAXN = ;
- const int M = MAXN * ;
- int n,q,m,TOT;
- int a[MAXN], t[MAXN];
- int T[M], lson[M], rson[M], c[M];
- void Init_hash()
- {
- for(int i = ; i <= n;i++)
- t[i] = a[i];
- sort(t+,t++n);
- m = unique(t+,t+n+)-t-;
- }
- int build(int l,int r)
- {
- int root = TOT++;
- c[root] = ;
- if(l != r)
- {
- int mid = (l+r)>>;
- lson[root] = build(l,mid);
- rson[root] = build(mid+,r);
- }
- return root;
- }
- int hash(int x)
- {
- return lower_bound(t+,t++m,x) - t;
- }
- int update(int root,int pos,int val)
- {
- int newroot = TOT++, tmp = newroot;
- c[newroot] = c[root] + val;
- int l = , r = m;
- while( l < r)
- {
- int mid = (l+r)>>;
- if(pos <= mid)
- {
- lson[newroot] = TOT++; rson[newroot] = rson[root];
- newroot = lson[newroot]; root = lson[root];
- r = mid;
- }
- else
- {
- rson[newroot] = TOT++; lson[newroot] = lson[root];
- newroot = rson[newroot]; root = rson[root];
- l = mid+;
- }
- c[newroot] = c[root] + val;
- }
- return tmp;
- }
- int query(int left_root,int right_root,int LCA,int k)
- {
- int lca_root = T[LCA];
- int pos = hash(a[LCA]);
- int l = , r = m;
- while(l < r)
- {
- int mid = (l+r)>>;
- int tmp = c[lson[left_root]] + c[lson[right_root]] - *c[lson[lca_root]] + (pos >= l && pos <= mid);
- if(tmp >= k)
- {
- left_root = lson[left_root];
- right_root = lson[right_root];
- lca_root = lson[lca_root];
- r = mid;
- }
- else
- {
- k -= tmp;
- left_root = rson[left_root];
- right_root = rson[right_root];
- lca_root = rson[lca_root];
- l = mid + ;
- }
- }
- return l;
- }
- //LCA部分
- int rmq[*MAXN];//rmq数组,就是欧拉序列对应的深度序列
- struct ST
- {
- int mm[*MAXN];
- int dp[*MAXN][];//最小值对应的下标
- void init(int n)
- {
- mm[] = -;
- for(int i = ;i <= n;i++)
- {
- mm[i] = ((i&(i-)) == )?mm[i-]+:mm[i-];
- dp[i][] = i;
- }
- for(int j = ; j <= mm[n];j++)
- for(int i = ; i + (<<j) - <= n; i++)
- dp[i][j] = rmq[dp[i][j-]] < rmq[dp[i+(<<(j-))][j-]]?dp[i][j-]:dp[i+(<<(j-))][j-];
- }
- int query(int a,int b)//查询[a,b]之间最小值的下标
- {
- if(a > b)swap(a,b);
- int k = mm[b-a+];
- return rmq[dp[a][k]] <= rmq[dp[b-(<<k)+][k]]?dp[a][k]:dp[b-(<<k)+][k];
- }
- };
- //边的结构体定义
- struct Edge
- {
- int to,next;
- };
- Edge edge[MAXN*];
- int tot,head[MAXN];
- int F[MAXN*];//欧拉序列,就是dfs遍历的顺序,长度为2*n-1,下标从1开始
- int P[MAXN];//P[i]表示点i在F中第一次出现的位置
- int cnt;
- ST st;
- void init()
- {
- tot = ;
- memset(head,-,sizeof(head));
- }
- void addedge(int u,int v)//加边,无向边需要加两次
- {
- edge[tot].to = v;
- edge[tot].next = head[u];
- head[u] = tot++;
- }
- void dfs(int u,int pre,int dep)
- {
- F[++cnt] = u;
- rmq[cnt] = dep;
- P[u] = cnt;
- for(int i = head[u];i != -;i = edge[i].next)
- {
- int v = edge[i].to;
- if(v == pre)continue;
- dfs(v,u,dep+);
- F[++cnt] = u;
- rmq[cnt] = dep;
- }
- }
- void LCA_init(int root,int node_num)//查询LCA前的初始化
- {
- cnt = ;
- dfs(root,root,);
- st.init(*node_num-);
- }
- int query_lca(int u,int v)//查询u,v的lca编号
- {
- return F[st.query(P[u],P[v])];
- }
- void dfs_build(int u,int pre)
- {
- int pos = hash(a[u]);
- T[u] = update(T[pre],pos,);
- for(int i = head[u]; i != -;i = edge[i].next)
- {
- int v = edge[i].to;
- if(v == pre)continue;
- dfs_build(v,u);
- }
- }
- int main()
- {
- //freopen("in.txt","r",stdin);
- //freopen("out.txt","w",stdout);
- while(scanf("%d%d",&n,&q) == )
- {
- for(int i = ;i <= n;i++)
- scanf("%d",&a[i]);
- Init_hash();
- init();
- TOT = ;
- int u,v;
- for(int i = ;i < n;i++)
- {
- scanf("%d%d",&u,&v);
- addedge(u,v);
- addedge(v,u);
- }
- LCA_init(,n);
- T[n+] = build(,m);
- dfs_build(,n+);
- int k;
- while(q--)
- {
- scanf("%d%d%d",&u,&v,&k);
- printf("%d\n",t[query(T[u],T[v],query_lca(u,v),k)]);
- }
- return ;
- }
- return ;
- }
LCA+主席树 (求树上路径点权第k大)的更多相关文章
- SPOJ 10628 Count on a tree(Tarjan离线LCA+主席树求树上第K小)
COT - Count on a tree #tree You are given a tree with N nodes.The tree nodes are numbered from 1 to ...
- SPOJ 10628 Count on a tree(Tarjan离线 | RMQ-ST在线求LCA+主席树求树上第K小)
COT - Count on a tree #tree You are given a tree with N nodes.The tree nodes are numbered from 1 to ...
- SPOJ COT(树上的点权第k大)
Count on a tree Time Limit: 129MS Memory Limit: 1572864KB 64bit IO Format: %lld & %llu Submi ...
- 主席树学习笔记(静态区间第k大)
题目背景 这是个非常经典的主席树入门题——静态区间第K小 数据已经过加强,请使用主席树.同时请注意常数优化 题目描述 如题,给定N个整数构成的序列,将对于指定的闭区间查询其区间内的第K小值. 输入输出 ...
- 【bzoj3123】[Sdoi2013]森林 倍增LCA+主席树+启发式合并
题目描述 输入 第一行包含一个正整数testcase,表示当前测试数据的测试点编号.保证1≤testcase≤20. 第二行包含三个整数N,M,T,分别表示节点数.初始边数.操作数.第三行包含N个非负 ...
- CodeForces - 840D:(主席树求出现区间出现次数大于某值的最小数)
Once, Leha found in the left pocket an array consisting of n integers, and in the right pocket q que ...
- 少年,想学带修改主席树吗 | BZOJ1901 带修改区间第k小
少年,想学带修改主席树吗 | BZOJ1901 带修改区间第k小 有一道题(BZOJ 1901)是这样的:n个数,m个询问,询问有两种:修改某个数/询问区间第k小. 不带修改的区间第k小用主席树很好写 ...
- BZOJ2588:LCA+主席树来实现树上两点之间第K大点权查询
对于每个节点维护这个节点到根的权值线段树 对于每个询问(x,y),这条路径上的线段树 tree[x]+tree[y]-tree[lca(x,y)]-tree[fa[lca(x,y)]] #includ ...
- UVALive - 7831 :ACM Tax (主席树求树路径上中位数:LCA+主席树)
题意:给定一棵带权树,Q次询问,每次询问路径上的中位数. 思路:中位数分边数奇偶考虑,当当边数为num=奇时,结果就算路径第num/2+1大,用主席树做即可... (做了几道比较难的主席树,都wa了. ...
随机推荐
- kafka基础四
消费者消费过程(二) 消费组状态机:消息的产生存储消费看似是杂乱无章的,但万物都会遵循一定的规则成长,任何事物的发展都是有迹可循的. 开始消费组初始状态为Stable,经过第一次Rebalance之后 ...
- iOS组件化开发· 什么是组件化
越来越多公司,开始了组件化,你还要等到什么时候...... 说到开发模式,我们最熟知的开发模式 MVC 或者最近比较热门的MVVM.但是我今天说的组件化的开发,其实MVC不是一类的.它其实是····· ...
- 将Android系统源码导入Android studio的方法
Android源码目录结构如下: |-- Makefile|-- abi (applicationbinary interface,应用程序二进制接口,生成libgabi++.so相关库文件)|-- ...
- css布局两边固定中间自适应的四种方法
第一种:左右侧采用浮动 中间采用margin-left 和 margin-right 方法. 代码如下: <div style="width:100%; margin:0 auto;& ...
- sublime快捷键mark
Ctrl+D 选词 (反复按快捷键,即可继续向下同时选中下一个相同的文本进行同时编辑)Ctrl+G 跳转到相应的行Ctrl+J 合并行(已选择需要合并的多行时)Ctrl+L 选择整行(按住-继续选择下 ...
- vijos 1448 校门外的树 (不是05年普及组那题)
描述 校门外有很多树,有苹果树,香蕉树,有会扔石头的,有可以吃掉补充体力的……如今学校决定在某个时刻在某一段种上一种树,保证任一时刻不会出现两段相同种类的树,现有两个操作:K=1,K=1,读入l.r表 ...
- 计算机图形学:贝塞尔曲线(Bezier Curve)
计算机图形学:贝塞尔曲线(Bezier Curve) 贝塞尔能由贝塞尔样条组合而成,也可产生更高维的贝塞尔曲面.
- ArcMap所有Command GUID
The information in this topic is useful if you're trying to programmatically find a built-in command ...
- ios坐标系统
在写程序的时候发现,iOS下的坐标.位置很容易弄乱,特别是在不同的坐标系统中,必须完成弄明白一些概念才能做相应的变化,例如CoreImage和UIView的坐标系统就截然不同,一个是以屏幕的左上角为原 ...
- 通过工厂模式批量创建对象后调用其中方法 出现XXXis not a function()问题原因
//通过工厂模式批量创建 function Computer(color,weight,logo){ var obj=new Object(); obj.color=c ...