【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\)重构树(具体是所有点按从小到大/从大到小的顺序,依次加入 ...
随机推荐
- yum 下载安装包以及依赖包
有时候我在用yum安装软件,依赖包比较多,还受网速的影响.所以我们可以将安装包以及依赖包下载到本地安装,这样会快捷很多. yum 提供了这种功能 yum -y install yum-utils 下载 ...
- 在动态组件上使用 keep-alive
----------------------html.js.style----------------------------------------------- <!DOCTYPE html ...
- Sentry 企业级数据安全解决方案 - Relay 项目配置
内容整理自官方文档 系列 Sentry 企业级数据安全解决方案 - Relay 入门 Sentry 企业级数据安全解决方案 - Relay 运行模式 Sentry 企业级数据安全解决方案 - Rela ...
- [转]Python3字符串前缀u、b、r
1.无前缀 & u前缀 字符串默认创建即以Unicode编码存储,可以存储中文. string = 'a' 等效于 string = u'a' Unicode中通常每个字符由2个字节表示 ...
- 用软碟通UltraISO刻录Win 10 1909 到U盘,只有1个G左右,安装不了系统
之前一直用软碟通刻录WIN10的ISO镜像到U盘.最近想到用最新版的WIN10 1909 来做一个U盘系统,刻录也成功了.就是安装系统的时候总报错,找了很久原因,终于发现刻录后占用U盘的空间只有1G左 ...
- HDU分拆素数和
https://acm.hdu.edu.cn/showproblem.php?pid=2098 时间复杂度 #include<bits/stdc++.h> using namespace ...
- 对极验geetest滑块验证码图片还原算法的研究
免责声明 本文章所提到的技术仅用于学习用途,禁止使用本文章的任何技术进行发起网络攻击.非法利用等网络犯罪行为,一切信息禁止用于任何非法用途.若读者利用文章所提到的技术实施违法犯罪行为,其责任一概由读者 ...
- jmu-ds-舞伴问题
假设在周末舞会上,男士和女士们分别进入舞厅,各自排成一队.跳舞开始,依次从男队和女队队头各出一人配成舞伴,若两队初始人数不同,则较长那一队未配对者等待下一轮舞曲.现要求写一算法模拟上述舞伴配对问题. ...
- winform GDI+ 抗锯齿
graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
- 【刷题-LeetCode】165 Compare Version Numbers
Compare Version Numbers Compare two version numbers version1 and version2. If *version1* > *versi ...