题目链接

大意

给出有\(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重构树 主席树)的更多相关文章

  1. BZOJ3545&3551[ONTAK2010]Peaks——kruskal重构树+主席树+dfs序+树上倍增

    题目描述 在Bytemountains有N座山峰,每座山峰有他的高度h_i.有些山峰之间有双向道路相连,共M条路径,每条路径有一个困难值,这个值越大表示越难走,现在有Q组询问,每组询问询问从点v开始只 ...

  2. luogu4197 Peaks (kruskal重构树+主席树)

    按照边权排序建出kruskal重构树,每次就变成了先找一个权值<=x的最远的祖先,然后看这个子树的第k小.离散化一下,在dfs序上做主席树即可 而且只需要建叶节点的主席树 注意输出的是第k小点的 ...

  3. 洛谷P4197 Peaks(Kruskal重构树 主席树)

    题意 题目链接 往后中文题就不翻译了qwq Sol 又是码农题..出题人这是强行把Kruskal重构树和主席树拼一块了啊.. 首先由于给出的限制条件是<=x,因此我们在最小生成树上走一定是最优的 ...

  4. 【BZOJ3551】【BZOJ3545】 【ONTAK2010】 Peaks (kruskal重构树+主席树)

    Description ​ 在\(Bytemountains\)有\(~n~\)座山峰,每座山峰有他的高度\(~h_i~\). 有些山峰之间有双向道路相连,共\(~m~\)条路径,每条路径有一个困难值 ...

  5. luoguP4197:Peaks(Kruskal重构树+主席树)或者(点分树+离线)

    题意:有N座山,M条道路.山有山高,路有困难值(即点权和边权).现在Q次询问,每次给出(v,p),让求从v出发,只能结果边权<=p的边,问能够到达的山中,第K高的高度(从大到小排序). 思路:显 ...

  6. 【BZOJ-3545&3551】Peaks&加强版 Kruskal重构树 + 主席树 + DFS序 + 倍增

    3545: [ONTAK2010]Peaks Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1202  Solved: 321[Submit][Sta ...

  7. [BZOJ3551][ONTAK2010]Peaks(加强版)(Kruskal重构树,主席树)

    3551: [ONTAK2010]Peaks加强版 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 2438  Solved: 763[Submit][ ...

  8. [luogu P4197] Peaks 解题报告(在线:kruskal重构树+主席树 离线:主席树+线段树合并)

    题目链接: https://www.luogu.org/problemnew/show/P4197 题目: 在Bytemountains有N座山峰,每座山峰有他的高度$h_i$.有些山峰之间有双向道路 ...

  9. LOJ.2865.[IOI2018]狼人(Kruskal重构树 主席树)

    LOJ 洛谷 这题不就是Peaks(加强版)或者归程么..这算是\(IOI2018\)撞上\(NOI2018\)的题了? \(Kruskal\)重构树(具体是所有点按从小到大/从大到小的顺序,依次加入 ...

随机推荐

  1. 使用uiautomatorviewer,查看app页面元素,进行元素定位

    环境搭建: 安装adt,安装成功后,就可以在adt路径下的tools文件夹中找到uiautomatorviewer.bat 用来做什么? uiautomatorviewer.bat是用来扫描和分析An ...

  2. DB2给表批量赋权

    使用DB2的for循环语句给表批量赋权,同理,稍加修改可作为其他批量操作. 值得注意的是: grant语句无法直接执行,需要使用execute immediate才能执行. 授权操作表的所有权限:gr ...

  3. Linux中ssh登陆慢的两种原因

    useDNS配置导致登陆慢 如果ssh server的配置文件(通常是 /etc/ssh/sshd_config )中设置 useDNS yes ,可能会导致 ssh 登陆卡住几十秒.将该配置项设为 ...

  4. 《剑指offer》面试题44. 数字序列中某一位的数字

    问题描述 数字以0123456789101112131415-的格式序列化到一个字符序列中.在这个序列中,第5位(从下标0开始计数)是5,第13位是1,第19位是4,等等. 请写一个函数,求任意第n位 ...

  5. sql多行合并一列

    with a as( select * from( select 1 userId , '天津' province union select 1 userId , '北京' union select ...

  6. 新手学习Java,如何快速从入门到精通!

    首先我要给你说的是,任何一个东西从零到精通,都是需要一个过程的,就相当于我们在小学的时候学乘法口诀表,背文言文一样,都是需要我们慢慢的去渡过这个阶段,我们才能慢慢的掌握,其次,毕竟这是一门编程语言,你 ...

  7. 多种语言tcp编程

    再次强调,最好socket编程 c#的tcpclient等封装无法对接android的socket服务器 c#的tcpclient等封装可对接java的socket服务器 python socket服 ...

  8. Ajax_Json用法

    Ajax_Json用法 关于json的服务端代码 //首先在方法里面设置一个响应json数据对象   const data = {       name:'chenxigua'   }​ //因为 s ...

  9. Mac系统之U盘重装(降级)

    U盘重装mac系统步骤如下 1. 将Mac系统U盘插上电脑,按下Mac开机键后,摁住"option"键不放,稍等几秒会出现启动盘选择界面,选择"安装 macOS" ...

  10. 通过location.search来获取页面传来的参数

    获取页面传来的参数 <div> <script> function GetQueryString(name) { var reg = new RegExp("(^|& ...