读题,只经过困难值小于等于x的路径,容易想到用Kruskal重构树;又要查询第k高的山峰,我们选择用主席树求解。

先做一棵重构树,跑一遍dfs,重构树中每一个非叶子节点对应一段区间,我们开range[x][0/1]数组来履行此职责,表示该节点维护的最左(最右)的叶子节点。每跑到一个叶子节点就把他插入主席树中。然后就是基本操作了,倍增找到我们想要的点,用该点的range来在主席树中查询即可。

按题目的困难值要求,显然重构树是个大根堆,用v数组存困难值。

下面的两个代码,一个是参考代码,注释很详细,一个是自己写的(差别可能不是很大)......

  1 #include<bits/stdc++.h>
2 using namespace std;
3 const int N=2e5+10;
4 const int M=5e5+10;
5 struct Node{
6 int u,v,w;
7 }e[M];
8 struct Edge{
9 int to,nxt;
10 }f[M<<1];
11 int n,m,q,fa[N],h[N][25],v[N],tot,cnt,head[N],rt[N<<5],ls[N<<5],rs[N<<5],a[N],b[N],sz,num,range[N][2],sum[N<<5];
12 int read(){
13 int x=0,ch=getchar();
14 while(ch<'0'||ch>'9') ch=getchar();
15 while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
16 return x;
17 }
18
19 bool cmp(Node a,Node b){
20 return a.w<b.w;//大根堆
21 }
22
23 int find(int x){
24 return fa[x]==x?x:fa[x]=find(fa[x]);
25 }
26
27 void add(int u,int v){
28 f[++cnt].to=v;
29 f[cnt].nxt=head[u];
30 head[u]=cnt;
31 }
32
33 void kruskal(){
34 for(int i=1;i<=2*n;i++) fa[i]=i;
35 sort(e+1,e+1+m,cmp);
36 tot=n;
37 for(int i=1;i<=m;i++){
38 int x=find(e[i].u),y=find(e[i].v);
39 if(x!=y){
40 fa[x]=fa[y]=++tot,v[tot]=e[i].w;
41 add(tot,x),add(tot,y);
42 h[x][0]=h[y][0]=tot;//处理ST
43 }
44 }
45 }
46
47 void build(int &x,int l,int r){//构建主席树的第0版本
48 x=++cnt;
49 if(l==r) return ;
50 int mid=l+r>>1;
51 build(ls[x],l,mid),build(rs[x],mid+1,r);
52 }
53
54 void update(int pre,int &rt,int l,int r,int k){//构建其他版本
55 rt=++cnt;
56 sum[rt]=sum[pre]+1;
57 if(l==r) return ;
58 int mid=l+r>>1;
59 if(k<=mid) rs[rt]=rs[pre],update(ls[pre],ls[rt],l,mid,k);
60 else ls[rt]=ls[pre],update(rs[pre],rs[rt],mid+1,r,k);//先复制,然后继续构建
61 }
62
63 void dfs(int x){
64 for(int i=1;i<=20;i++) h[x][i]=h[h[x][i-1]][i-1];//处理ST
65 range[x][0]=num;//每个非叶子节点所维护的最左叶子节点
66 if(!head[x]){//x是叶子节点
67 int k=lower_bound(b+1,b+sz+1,a[x])-b;
68 range[x][0]=++num;
69 update(rt[num-1],rt[num],1,sz,k);//每找到一个叶子节点,就构建新的主席树版本
70 return ;
71 }
72 for(int i=head[x];i;i=f[i].nxt)
73 dfs(f[i].to);
74 range[x][1]=num;//x子树中的点遍历完了,他维护的最右叶子节点的值就是num
75 }
76
77 int query(int x,int y,int l,int r,int k){
78 if(l==r) return l;//找到答案了
79 int mid=l+r>>1,q=sum[rs[y]]-sum[rs[x]];
80 if(k<=q) return query(rs[x],rs[y],mid+1,r,k);
81 else return query(ls[x],ls[y],l,mid,k-q);//注意题目要求找第k大的
82 }
83
84 int main(){
85 n=read(),m=read(),q=read();
86 for(int i=1;i<=n;i++) a[i]=b[i]=read();
87 sort(b+1,b+n+1);
88 sz=unique(b+1,b+n+1)-b-1;//离散化
89 for(int i=1;i<=m;i++)
90 e[i].u=read(),e[i].v=read(),e[i].w=read();
91 kruskal();//重构树
92 cnt=0;
93 build(rt[0],1,sz);
94 dfs(tot);//从重构树的根开始遍历
95 while(q--){//处理每次询问
96 int x=read(),y=read(),z=read();
97 for(int i=20;i>=0;i--)//倍增
98 if(h[x][i]&&v[h[x][i]]<=y) x=h[x][i];
99 if(range[x][1]-range[x][0]<z) cout<<-1<<endl;//无解
100 else cout<<b[query(rt[range[x][0]],rt[range[x][1]],1,sz,z)]<<endl;
101 }
102 return 0;
103 }

自己写的丑代码......

  1 #include<bits/stdc++.h>
2 using namespace std;
3 const int N=2e5+10;
4 const int M=5e5+10;
5 struct node{
6 int u,v,w;
7 bool operator<(const node &b) const{return w<b.w;}
8 }e[M];
9 struct edge{
10 int to,nex;
11 }tmp[M<<1];
12 int n,m,q,fa[N],h[N][25],v[N],cnt,tot,num,res,head[N],rt[N<<5],ls[N<<5],rs[N<<5];
13 int a[N],b[N],sz,range[N][2],sum[N<<5];
14 inline int read(){
15 int x=0;char ch=getchar();
16 while(ch<'0'||ch>'9') ch=getchar();
17 while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
18 return x;
19 }
20
21 inline void add(int x,int y){
22 tmp[++tot].nex=head[x];
23 head[x]=tot;
24 tmp[tot].to=y;
25 }
26
27 inline int find(int x){
28 return x==fa[x]?x:fa[x]=find(fa[x]);
29 }
30
31 inline void kruskal(){
32 sort(e+1,e+m+1);
33 cnt=n;
34 for(int i=1;i<=(n<<1);i++) fa[i]=i;
35 for(int i=1;i<=m;i++){
36 int fu=find(e[i].u),fv=find(e[i].v);
37 if(fu!=fv){
38 fa[fu]=fa[fv]=++cnt;
39 v[cnt]=e[i].w;
40 add(cnt,fu),add(cnt,fv);
41 h[fu][0]=h[fv][0]=cnt;
42 }
43 }
44 }
45
46 inline void build(int &x,int l,int r){
47 x=++num;
48 if(l==r) return ;
49 int mid=l+r>>1;
50 build(ls[x],l,mid),build(rs[x],mid+1,r);
51 }
52
53 inline void update(int x,int &y,int l,int r,int k){
54 y=++num;
55 sum[y]=sum[x]+1;
56 if(l==r) return ;
57 int mid=l+r>>1;
58 if(k<=mid) rs[y]=rs[x],update(ls[x],ls[y],l,mid,k);
59 else ls[y]=ls[x],update(rs[x],rs[y],mid+1,r,k);
60 }
61
62 inline void dfs(int x){
63 for(int i=1;i<=20;i++) h[x][i]=h[h[x][i-1]][i-1];
64 range[x][0]=res;
65 if(!head[x]){
66 int k=lower_bound(b+1,b+sz+1,a[x])-b;
67 range[x][0]=++res;
68 update(rt[res-1],rt[res],1,sz,k);
69 return ;
70 }
71 for(int i=head[x];i;i=tmp[i].nex)
72 dfs(tmp[i].to);
73 range[x][1]=res;
74 }
75
76 inline int query(int x/*左边*/,int y/*右边*/,int l,int r,int k){
77 if(l==r) return l;
78 int mid=l+r>>1;
79 int s=sum[rs[y]]-sum[rs[x]];
80 if(k<=s) return query(rs[x],rs[y],mid+1,r,k);
81 else return query(ls[x],ls[y],l,mid,k-s);
82 }
83
84 int main(){
85 n=read(),m=read(),q=read();
86 for(int i=1;i<=n;i++) a[i]=b[i]=read();
87 sort(b+1,b+n+1);
88 sz=unique(b+1,b+n+1)-b-1;
89 for(int i=1;i<=m;i++){
90 e[i].u=read(),e[i].v=read(),e[i].w=read();
91 }
92 kruskal();
93 build(rt[0],1,sz);
94 dfs(cnt);
95 while(q--){
96 int x=read(),y=read(),z=read();
97 for(int i=20;i>=0;i--){
98 if(h[x][i]&&v[h[x][i]]<=y) x=h[x][i];
99 }
100 if(range[x][1]-range[x][0]<z) cout<<-1<<endl;
101 else cout<<b[query(rt[range[x][0]],rt[range[x][1]],1,sz,z)]<<endl;
102 }
103 return 0;
104 }

重构树的节点原来还可以维护区间的左右端点啊(垃圾的我才知道)......

洛谷P4197 Peaks (Kruskal重构树)的更多相关文章

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

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

  2. [ONTAK2010]Peaks kruskal重构树,主席树

    [ONTAK2010]Peaks kruskal重构树练手题. LG传送门竟然不强制在线?看到离线水过很不爽:B站强制在线版传送门 看到"询问从点\(v\)开始只经过困难值小于等于\(x\) ...

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

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

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

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

  5. bzoj 3545: [ONTAK2010]Peaks Kruskal重构树

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

  6. 【BZOJ3545】Peaks(Kruskal重构树 主席树)

    题目链接 大意 给出有\(N\)个点\(M\)条边的一张图,其中每个点都有一个High值,每条边都有一个Hard值. 再给出\(Q\)个询问:\(v\) \(x\) \(k\) 每次询问查询从点\(v ...

  7. 洛谷P4197 Peaks&&克鲁斯卡尔重构树学习笔记(克鲁斯卡尔重构树+主席树)

    传送门 据说离线做法是主席树上树+启发式合并(然而我并不会) 据说bzoj上有强制在线版本只能用克鲁斯卡尔重构树,那就好好讲一下好了 这里先感谢LadyLex大佬的博客->这里 克鲁斯卡尔重构树 ...

  8. BZOJ 3545 / 洛谷 P4197 Peaks 解题报告

    P4197 Peaks 题目描述 在\(\text{Bytemountains}\)有\(N\)座山峰,每座山峰有他的高度\(h_i\).有些山峰之间有双向道路相连,共\(M\)条路径,每条路径有一个 ...

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

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

随机推荐

  1. Java开发学习(十八)----AOP通知获取数据(参数、返回值、异常)

    前面的博客我们写AOP仅仅是在原始方法前后追加一些操作,接下来我们要说说AOP中数据相关的内容,我们将从获取参数.获取返回值和获取异常三个方面来研究切入点的相关信息. 前面我们介绍通知类型的时候总共讲 ...

  2. JAVA定时任务原理入门

    本文适用语言:java 序章:定时任务实现方式 当下,java编码过程中,实现定时任务的方式主要以以下两种为主 spring框架的@Scheduled quzrtz框架 网络上关于这两种框架的实践和配 ...

  3. mysql 存储过程和触发器

    存储过程 -- 声明结束符 -- 创建存储过程 DELIMITER $ -- 声明存储过程的结束符 CREATE PROCEDURE pro_test() --存储过程名称(参数列表) BEGIN - ...

  4. RSS订阅微信公众号初探-feed43

    为什么用RSS,能怎么用RSS订阅微信公众号 建议信息聚合(Really Simple Syndication, RSS)在08年我第一次摸到自己家电脑时就给我留下了印象,当时还想这打开都啥玩意呀怎么 ...

  5. DP 优化方法合集

    0. 前言 写完这篇文章后发现自己对于 DP 的优化一窍不通,所以补了补 DP 的一些优化,写篇 blog 总结一下. 1. 单调队列/单调栈优化 1.2 算法介绍 这应该算是最基础的 DP 优化方法 ...

  6. Apache DolphinScheduler 1.3.9 发布,新增 StandaloneServer

    点击上方 蓝字关注我们 2021 年 10 月 22 日,Apache DolphinScheduler 正式发布 1.3.9 版本.时隔一个半月,在社区贡献者的共同努力下,Apache Dolphi ...

  7. 【活动专辑】Gitee X DolphinScheduler 邀你一起参与 issue 解决赢好礼!

    在你参与 DolphinScheduler 项目开发时,是否曾因为这些问题困惑: 对项目感兴趣,但不清楚自己可以为项目做什么 在众多 issue 中,找不到合适自己参与的 issue 任务 认为参与开 ...

  8. pnpm 的 workspace 实现 monorepo 工程

    前言 前端多个包管理的的方式一般都是采用monorepo的方式去管理,之前都是使用的lerna的workspace去管理.这段时间包管理切换到了pnpm上,它也有worksapce,可以支持monor ...

  9. 我写的蓝宝石留言本php版 v4.5

    蓝宝石留言本php版v4.5采用原生php编写,在php5.6~php7.x下调试通过.本留言本使用了utf-8编码. include/config1.php是数据库连接参数的配置文件, includ ...

  10. C++大数据的读写

    当一个文件1G以上的这种,使用内存文件映射会提高读写效率: 下边时段出自<windows核心编程>,读取一个大文件,然后统计里边字符出现次数的函数: __int64 CountOs(voi ...