【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\)重构树(具体是所有点按从小到大/从大到小的顺序,依次加入 ...
随机推荐
- linux系统内置函数
一.action函数 在/etc/init.d/functions中有一个系统自带的函数 source /etc/init.d/functions #启用系统函数脚本 action "输出 ...
- ES6扩展运算符(...)
来自为知笔记(Wiz)
- k8s 理解Service工作原理
什么是service? Service是将运行在一组 Pods 上的应用程序公开为网络服务的抽象方法. 简单来说K8s提供了service对象来访问pod.我们在<k8s网络模型与集群通信> ...
- VM和CentOS7安装教程
如果图片损坏,点击链接:https://www.toutiao.com/i6491076101664670222/ 安装软件 VMware_workstation_full_12.5.2 CentOS ...
- 记一次ARM服务器(鲲鹏920)的PXE批量装机遇到的坑
由于近期项目需要,在对一批华为鲲鹏920的ARM服务器(型号为天宫TG225 B1)进行批量装机的过程中,遇到了各种各样千奇百怪的bug(换个高情商的说法就是遇到了各种各样和x86服务器不一样的地方) ...
- 论文翻译:2020_FLGCNN: A novel fully convolutional neural network for end-to-end monaural speech enhancement with utterance-based objective functions
论文地址:FLGCNN:一种新颖的全卷积神经网络,用于基于话语的目标函数的端到端单耳语音增强 论文代码:https://github.com/LXP-Never/FLGCCRN(非官方复现) 引用格式 ...
- 信息收集&Fuzz
本文译自https://0xjoyghosh.medium.com/information-gathering-scanning-for-sensitive-information-reloaded- ...
- 为什么char类型输入遇空格会结束,int类型必须要空格才能输出
char类型与int类型输入时的区别: 在C语言的规则中,规定了scanf函数在接收字符串时--遇到空格或回车就认为前面的输入已经完成且有效! 而对于int类型:表示整数,输入时需要用空格隔开,以确认 ...
- 【一个小实验】腾讯云的redis的主从结构的特性
使用腾讯云上的redis,可以添加多个备机的分片,并且可以选择不同的账号来设定主从读写的策略. 现在设置两个账号:primary-主节点写,主节点读:secondary-主节点写,从节点读. 研究出了 ...
- 【记录一个问题】android下的ucontext协程,因为使用栈上的对象,导致cv::Mat被莫名析构
工作的流程是这样:某个协程在栈上创建task对象,在task对象内有需要返回的cv::Mat. 然后把task放到另一个线程上去执行,然后切换到别的协程,等到工作线程执行完task后,再唤醒协程. 这 ...