【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\)重构树(具体是所有点按从小到大/从大到小的顺序,依次加入 ...
随机推荐
- .net core中Grpc使用报错:The response ended prematurely.
当我们调用Grpc是出现下面的一堆异常时,一般是由于LTS导致的: Call failed with gRPC error status. Status code: 'Unavailable', Me ...
- hisql 与sqlsugar,freesql 数据插入性能测试
hisql与目前比较流行的ORM框架性能测试对比 hisql 一直定位为新一代的ORM框架 为低代码开发而生 测试数据数据库为sqlserver数据库 测试源码地址hisql与sqlsugar fre ...
- Pytest_测试用例的执行方式(2)
在pytest框架中,编写测试用例有如下约束: 所有的测试用例文件名都需要满足test_*.py格式或*_test.py格式. 在测试用例文件中,测试类以Test开头,并且不能带有__init__方法 ...
- 适配器模式(pthon)
#!/usr/bin/env python3 # -*- coding: utf-8 -*- # adapter_pattern.py # 适配器模式 class Adaptee: def reque ...
- $.ajax传输js数组,spring接收异常
今天测试,出现一个奇怪的问题 $.ajax传输js数组,spring接收这个数组,出现奇怪的现象,如果数组只有一个元素,且这个元素字符串最后一个字符是以逗号,结尾的话, spring会自动把这个逗号去 ...
- 实验 6 :OpenDaylight 实验——OpenDaylight 及 Postman实现流表下发
实验 6 :OpenDaylight 实验--OpenDaylight 及 Postman实现流表下发 一.实验目的 熟悉 Postman 的使用:熟悉如何使用 OpenDaylight 通过 Pos ...
- Golang实现集合(set)
package set package set import ( "bytes" "fmt" "sync" ) type Set struc ...
- 【Spring专场】「MVC容器」不看源码就带你认识核心流程以及运作原理
前提回顾 之前已经写了很多问斩针对于SpringMVC的的执行原理和核心流程,在此再进行冗余介绍就没有任何意义了,所以我们主要考虑的就是针对于SpringMVC还没但大框架有介绍的相关内容解析分析和说 ...
- MySQL常用内置函数整理
[1]@@datadir 函数作用:返回数据库的存储目录构造SQL语句 select @@datadir;ps:@@basedir返回mysql的根目录[2]@@version_compile_os ...
- JVM调优-1
JVM运行参数 在jvm中有很多的参数可以进行设置,这样可以让jvm在各种环境中都能够高效的运行.绝大部分的参数保持默认即可. 三种参数类型 标准参数 -help -version -X参数(非标准参 ...