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了. ...
随机推荐
- 集合框架比较两个对象是否相同(equals和hashCode方法)
package com.dcz.hashset; import java.util.HashSet; import java.util.Set; /** * HashSet是接口最常用的实现类,顾名思 ...
- hybrid app开发中:苹果移动设备实用Meta标签
hybrid app开发中:苹果移动设备实用Meta标签 “apple-mobile-web-app-status-bar-style”作用是控制状态栏显示样式 具体效果如下: status-bar- ...
- WEB 前端菜鸟,感觉很迷茫,该怎么做?
前几天看到这样的问题 先说问题吧:感觉前端涉及到的东西太多了,自己也很浮躁,看了挺多书,可是代码缺敲得却不多.技术菜,又什么都想学,比如现在纠结要不要先学scss或者php或者angularjs,ba ...
- Android Studio报错Unable to resolve dependency for ':app@release/compileClasspath':无法引用任何外部依赖的解决办法
Android Studio 在引用外部依赖时,发现一直无法引用外部依赖.刚开始以为是墙的问题,尝试修改Gradle配置,未解决问题. 最终发现原来是在Android Sudio安装优化配置时,将Gr ...
- jsp中<c:forEach varStatus="status">的属性值问题
c:forEach varStatus属性 current当前这次迭代的(集合中的)项 index当前这次迭代从 0 开始的迭代索引 count当前这次迭代从 1 开始的迭代计数 first用来表明当 ...
- pyhton中的__new__和__init__
首先__new__() 函数只能用于从object继承的新式类:其次,object将__new__()方法定义为静态方法,并且至少需要传递一个参数cls,cls表示需要实例化的类,此参数在实例化时由P ...
- IOS自动化测试之UIAutomation
通过Xcode工具编写运行测试脚本 1.当你有了一个应用的源代码之后,在Xcode工具中,首先选中被测应用,然后点击菜单栏中的“Product-Profile”,则会弹出Instruments工具,在 ...
- KTU Programming Camp (Winter Training Day 1)
A.B.C(By musashiheart) 0216个人赛前三道题解 E(By ggg) Gym - 100735E Restore H(by pipixia) Gym - 100735H
- 多源最短路径 – Floyd-Warshall Algorithm
介绍: 是解决任意两点间的最短路径的一种算法,可以正确处理有向图或负权(但不可存在负权回路)的最短路径问题,同时也被用于计算有向图的传递闭包. Floyd-Warshall算法的时间复杂度是O(N3) ...
- 特别困的学生 UVa12108(模拟题)
一.题目 课堂上有n个学生(n<=10).每个学生都有一个“睡眠-清醒”周期,其中第i个学生醒Ai分钟后睡Bi分钟,然后重复(1<=Ai,Bi<=5),初始第i个同学处于他的周期的C ...