【BZOJ3545】Peaks(Kruskal重构树 主席树)
大意
给出有\(N\)个点\(M\)条边的一张图,其中每个点都有一个High值,每条边都有一个Hard值。
再给出\(Q\)个询问:\(v\) \(x\) \(k\)
每次询问查询从点\(v\)出发,只经过Hard值小于等于\(x\)的边能到达的点中,第\(k\)大的High值。
思路
考虑Kruskal重构树:
在Kruskal算法求最小生成树的时候,每次加边将该边化成一个点,该点的点权值是原边权值。
然后用该点与两个连通块连边。
如图:

变为:

(左侧为点编号,右侧为点权)
这样重建一颗树后,可以发现其是一个大根堆。(根权最大)
然后我们就可以用倍增的思想在\(O(log(N))\)的时间内求出对于一对\((v,x)\)的上界。
(小注:上界指以该上界为根的子树内的点都可以被这对\((v,x)\)访问到)
在用Kruskal重构后,我们就可以将该问题变为求一颗子树内第\(K\)大的点权值。
对于这个问题,我们可以用主席树维护前缀的权值线段树,查询一颗子树时用DFN序就行了。
代码
附上一篇很慢的代码
#include<map>
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
const int MAXK=25;
const int MAXN=200005;
const int MAXM=500005;
int N,M,Q,Cnt,NCnt,PCnt,Root[MAXN];
int A[MAXN],Fa[MAXN],Val[MAXN];
int Dfn[MAXN],Tid[MAXN],Siz[MAXN];
int fa[MAXN][MAXK],Vat[MAXN][MAXK];
struct Edge{int x,y,z;}s[MAXM];
struct Quer{int p,x,k;}q[MAXM];
struct Node{int num,ch[2],l,r;}t[MAXM*120];
bool cmp(Edge X,Edge Y){return X.z<Y.z;}
int Find(int x){return Fa[x]==x?x:Fa[x]=Find(Fa[x]);}
int Len,B[MAXN],E[MAXN],ValCnt;
vector<int>P[MAXN];
map<int,int>Mp;
void Val_Init(){
sort(B+1,B+Len+1);B[0]=-1;
for(int i=1;i<=Len;i++)
if(B[i]!=B[i-1]){
Mp[B[i]]=++ValCnt;
E[ValCnt]=B[i];
}
for(int i=1;i<=Cnt;i++)A[i]=Mp[A[i]];
}
void DFS(int u){
Dfn[u]=++NCnt;
Tid[NCnt]=u;Siz[u]=1;
int size=P[u].size();
for(int i=0;i<size;i++){
int v=P[u][i];
fa[v][0]=u;DFS(v);
Vat[v][0]=max(Val[v],Val[u]);
Siz[u]+=Siz[v];
}
}
void Build(int &rt,int l,int r){
rt=++PCnt;
t[rt].l=l;t[rt].r=r;
if(l==r)return ;
int mid=(l+r)/2;
Build(t[rt].ch[0],l,mid);
Build(t[rt].ch[1],mid+1,r);
}
void Insert(int &rt,int ort,int p,int val){
rt=++PCnt;t[rt]=t[ort];t[rt].num++;
if(t[rt].l==t[rt].r)return ;
int mid=(t[rt].l+t[rt].r)>>1;
if(p<=mid)Insert(t[rt].ch[0],t[ort].ch[0],p,val);
else Insert(t[rt].ch[1],t[ort].ch[1],p,val);
}
int Find(int rt1,int rt2,int k){
if(t[rt1].l==t[rt1].r)return t[rt1].l;
int num=t[t[rt1].ch[0]].num-t[t[rt2].ch[0]].num;
if(num>=k)return Find(t[rt1].ch[0],t[rt2].ch[0],k);
return Find(t[rt1].ch[1],t[rt2].ch[1],k-num);
}
int Get(int p,int x){
for(int i=20;i>=0;i--)
if(Vat[p][i]<=x&&fa[p][i])
p=fa[p][i];
return p;
}
void Init(){
sort(s+1,s+M+1,cmp);Cnt=N;
for(int i=1;i<=M;i++){
int x=Find(s[i].x);
int y=Find(s[i].y);
if(x==y)continue;
Fa[x]=++Cnt;Fa[y]=Cnt;
Val[Cnt]=s[i].z;
P[Cnt].push_back(x);
P[Cnt].push_back(y);
}
Val_Init();
for(int i=1;i<=Cnt;i++)
if(Fa[i]==i)DFS(i);
for(int k=1;k<=20;k++)
for(int i=1;i<=Cnt;i++){
fa[i][k]=fa[fa[i][k-1]][k-1];
Vat[i][k]=max(Vat[i][k-1],Vat[fa[i][k-1]][k-1]);
}
PCnt=-1;
Build(Root[0],1,ValCnt);
for(int i=1;i<=Cnt;i++){
if(A[Tid[i]]==1){
Root[i]=Root[i-1];
continue;
}
Insert(Root[i],Root[i-1],A[Tid[i]],1);
}
}
int main(){
scanf("%d%d%d",&N,&M,&Q);
for(int i=1;i<=N;i++)
scanf("%d",&A[i]),B[++Len]=A[i];B[++Len]=0;
for(int i=1;i<=2*N;i++)Fa[i]=i;
for(int i=1;i<=M;i++)
scanf("%d%d%d",&s[i].x,&s[i].y,&s[i].z);
for(int i=1;i<=Q;i++)
scanf("%d%d%d",&q[i].p,&q[i].x,&q[i].k);
Init();
for(int i=1;i<=Q;i++){
int Tp=Get(q[i].p,q[i].x);
int rt1=Root[Dfn[Tp]+Siz[Tp]-1],rt2=Root[Dfn[Tp]-1];
int num=t[rt1].num-t[rt2].num;
if(num<q[i].k){
printf("-1\n");
continue;
}
int ret=Find(rt1,rt2,num-q[i].k+1);
printf("%d\n",E[ret]);
}
}
【BZOJ3545】Peaks(Kruskal重构树 主席树)的更多相关文章
- BZOJ3545&3551[ONTAK2010]Peaks——kruskal重构树+主席树+dfs序+树上倍增
题目描述 在Bytemountains有N座山峰,每座山峰有他的高度h_i.有些山峰之间有双向道路相连,共M条路径,每条路径有一个困难值,这个值越大表示越难走,现在有Q组询问,每组询问询问从点v开始只 ...
- luogu4197 Peaks (kruskal重构树+主席树)
按照边权排序建出kruskal重构树,每次就变成了先找一个权值<=x的最远的祖先,然后看这个子树的第k小.离散化一下,在dfs序上做主席树即可 而且只需要建叶节点的主席树 注意输出的是第k小点的 ...
- 洛谷P4197 Peaks(Kruskal重构树 主席树)
题意 题目链接 往后中文题就不翻译了qwq Sol 又是码农题..出题人这是强行把Kruskal重构树和主席树拼一块了啊.. 首先由于给出的限制条件是<=x,因此我们在最小生成树上走一定是最优的 ...
- 【BZOJ3551】【BZOJ3545】 【ONTAK2010】 Peaks (kruskal重构树+主席树)
Description 在\(Bytemountains\)有\(~n~\)座山峰,每座山峰有他的高度\(~h_i~\). 有些山峰之间有双向道路相连,共\(~m~\)条路径,每条路径有一个困难值 ...
- luoguP4197:Peaks(Kruskal重构树+主席树)或者(点分树+离线)
题意:有N座山,M条道路.山有山高,路有困难值(即点权和边权).现在Q次询问,每次给出(v,p),让求从v出发,只能结果边权<=p的边,问能够到达的山中,第K高的高度(从大到小排序). 思路:显 ...
- 【BZOJ-3545&3551】Peaks&加强版 Kruskal重构树 + 主席树 + DFS序 + 倍增
3545: [ONTAK2010]Peaks Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1202 Solved: 321[Submit][Sta ...
- [BZOJ3551][ONTAK2010]Peaks(加强版)(Kruskal重构树,主席树)
3551: [ONTAK2010]Peaks加强版 Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 2438 Solved: 763[Submit][ ...
- [luogu P4197] Peaks 解题报告(在线:kruskal重构树+主席树 离线:主席树+线段树合并)
题目链接: https://www.luogu.org/problemnew/show/P4197 题目: 在Bytemountains有N座山峰,每座山峰有他的高度$h_i$.有些山峰之间有双向道路 ...
- LOJ.2865.[IOI2018]狼人(Kruskal重构树 主席树)
LOJ 洛谷 这题不就是Peaks(加强版)或者归程么..这算是\(IOI2018\)撞上\(NOI2018\)的题了? \(Kruskal\)重构树(具体是所有点按从小到大/从大到小的顺序,依次加入 ...
随机推荐
- 造轮子-strace(二)实现
这一篇文章会介绍strace如何工作,再稍微深入介绍一下什么是system call.再介绍一下ptrace.wait(strace依赖的system call).最后再一起来造个轮子,动手用代码实现 ...
- linux如何查看服务器当前的并发访问量
linux如何查看服务器当前的并发访问量 [root@localhost ~]# netstat -pnt | grep :80 | wc -l 2 [root@localhost ~]# netst ...
- spring cloud --- Zuul --- 心得
spring boot 1.5.9.RELEASE spring cloud Dalston.SR1 1.前言 什么是 Zuul? Zuul是微服务网关,与Gateway类似 ,根据请 ...
- Python的内存管理和垃圾回收机制
内存管理 Python解释器由c语言开发完成,py中所有的操作最终都由底层的c语言来实现并完成,所以想要了解底层内存管理需要结合python源码来进行解释. 1. 两个重要的结构体 include/o ...
- vue特效网站集锦
1.17素材网 http://www.17sucai.com/pins/tag/7012.html
- 微信小程序base64图片保存到手机相册
问题:base64图片不能直接用wx.saveImageToPhotosAlbum保存到手机相册 解决: 先用fs.writeFile写入本地文件,再wx.saveImageToPhotosAlbum ...
- [流畅的Python]第一章数据模型
这些来自同一家出版社的动物书 像是计算机科学界一盏盏指路明灯 余幼时 初试读 学浅 以为之晦涩难懂 像是老学究咬文嚼字 现在看起来还有些有趣 其实理工男大多都很有趣 这一章介绍了 怎么样去视线一个带有 ...
- 我选择了MySQL和SpringData JPA
我是3y,一年CRUD经验用十年的markdown程序员常年被誉为优质八股文选手 今天想跟大家聊聊数据库层面上的事,austin项目继续更新(注:今天聊的数据库都特指关系型数据库) 01.数据库选择 ...
- 【刷题-LeetCode】289. Game of Life
Game of Life According to the Wikipedia's article: "The Game of Life, also known simply as Life ...
- Python中的路径
转义 windows路径使用的是\,linux路径使用的是/. 特别的,在windows系统中如果有这样的一个路径 D:\nxxx\txxx\x1,程序会报错.因为在路径中存在特殊符 \n(换行符)和 ...