传送门

据说离线做法是主席树上树+启发式合并(然而我并不会)

据说bzoj上有强制在线版本只能用克鲁斯卡尔重构树,那就好好讲一下好了

这里先感谢LadyLex大佬的博客->这里

克鲁斯卡尔重构树可以用来解决一类诸如“查询从某个点出发经过边权不超过val的边所能到达的节点”的问题

首先不难发现,上面这个问题肯定是在最小生成树上走最优,其他边都可以不用去管

那么我们就在建最小生成树的时候搞事情

克鲁斯卡尔重构树的思想就是在建最小生成树的时候不是直接连边,而是新建一个节点,并把这个节点的值设为边权,然后令两个连通块的代表点分别作为它的左右儿子。然后令这个新节点成为整个连通块的代表点

说了那么多跟没说一样……举个栗子好了

假设现在有四个节点,要求他们的克鲁斯卡尔重构树

我们按最小生成树的方法找,先把边按权值从小到大排序。

然后设第一条边权值为4,连接1和2这两个连通块

然后新建一个节点5,点权设为4,并把1和2作为他的左右儿子

第二条边权值为6,连接3和4这两个连通块

然后新建一个节点6,点权设为6,并把3和4作为他的左右儿子

第三条边权值为7,连接1和2,那么我们就是要把4和6的连通块相连了(这两个是连通块的代表点)

然后新建一个节点7,点权设为7,并把5和6作为他的左右儿子

然后这一棵克鲁斯卡尔重构树就建好了٩(๑>◡<๑)۶

不难发现它有一个性质,每一个儿子节点的权值都小于等于自己的权值(因为我们是按最小生成树的顺序建的)

那么要查“查询从某个点出发经过边权不超过val的边所能到达的节点”

因为我们一个原来图上的点肯定是叶子结点,所以我们只要从叶子结点开始往上找,直到找到最后一个点权小于等于$val$的点

那么这个点为根的子树里的所有点都能到达

怎么找呢?倍增就行了

放到这一题里,因为要查询第$k$大,所以还得套个主席树上树

然而就差不多了

 //minamoto
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
char buf[<<],*p1=buf,*p2=buf;
inline int read(){
#define num ch-'0'
char ch;bool flag=;int res;
while(!isdigit(ch=getc()))
(ch=='-')&&(flag=true);
for(res=num;isdigit(ch=getc());res=res*+num);
(flag)&&(res=-res);
#undef num
return res;
}
char sr[<<],z[];int C=-,Z;
inline void Ot(){fwrite(sr,,C+,stdout),C=-;}
inline void print(int x){
if(C><<)Ot();if(x<)sr[++C]=,x=-x;
while(z[++Z]=x%+,x/=);
while(sr[++C]=z[Z],--Z);sr[++C]='\n';
}
const int N=2e5+,M=N*,K=5e5+;
struct node{
int from,to,cost;
node(){}
node(int from,int to,int cost):from(from),to(to),cost(cost){}
inline bool operator <(const node &b)const
{return cost<b.cost;}
}E[K];
int head[N],Next[N],ver[N],sum[M],L[M],R[M],bin[],cnt,tot;
int fa[N],f[N][],ls[N],rs[N],rt[N],val[N],num;
int h[N],limit,b[N],n,q,m,ans=,dfn;
inline void mission(int u){
for(int i=;bin[i]<=n;++i)
f[u][i]=f[f[u][i-]][i-];
}
inline void add(int u,int v){
ver[++tot]=v,Next[tot]=head[u],head[u]=tot;
}
int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
void update(int last,int &now,int l,int r,int x){
sum[now=++cnt]=sum[last]+;
if(l==r) return;
int mid=(l+r)>>;
if(x<=mid) R[now]=R[last],update(L[last],L[now],l,mid,x);
else L[now]=L[last],update(R[last],R[now],mid+,r,x);
}
int query(int a,int x,int k){
int l=,r=limit;
for(int j=;~j;--j)
if(f[a][j]&&val[f[a][j]]<=x) a=f[a][j];
int v=rt[rs[a]],u=rt[ls[a]-];
if(sum[v]-sum[u]<k) return -;
while(l<r){
int tmp=sum[R[v]]-sum[R[u]],mid=(l+r)>>;
if(tmp>=k) v=R[v],u=R[u],l=mid+;
else v=L[v],u=L[u],r=mid,k-=tmp;
}
return b[r];
}
void dfs(int u){
mission(u),ls[u]=++num;
if(u<=n) update(rt[num-],rt[num],,limit,h[u]);
else rt[num]=rt[num-];
for(int i=head[u];i;i=Next[i]) dfs(ver[i]);
rs[u]=num;
}
int main(){
// freopen("testdata.in","r",stdin);
n=read(),m=read(),q=read();
bin[]=;for(int i=;i<=;++i) bin[i]=bin[i-]<<;
for(int i=;i<=*n;++i) fa[i]=i;
for(int i=;i<=n;++i) b[i]=h[i]=read();
for(int i=,u,v,e;i<=m;++i)
u=read(),v=read(),e=read(),E[i]=node(u,v,e);
sort(b+,b++n),limit=unique(b+,b++n)-b-;
for(int i=;i<=n;++i) h[i]=lower_bound(b+,b++limit,h[i])-b;
sort(E+,E++m);dfn=n;
for(int i=;i<=m;++i){
int u=find(E[i].from),v=find(E[i].to);
if(u!=v){
val[++dfn]=E[i].cost,fa[u]=fa[v]=dfn;
add(dfn,u),add(dfn,v),f[u][]=f[v][]=dfn;
if(dfn-n==n-) break;
}
}
for(int i=;i<=dfn;++i) if(!ls[i]) dfs(find(i));
while(q--){
int v=read(),x=read(),k=read();
print(query(v,x,k));
}
Ot();
return ;
}

洛谷P4197 Peaks&&克鲁斯卡尔重构树学习笔记(克鲁斯卡尔重构树+主席树)的更多相关文章

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

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

  2. 洛谷P4197 Peaks (Kruskal重构树)

    读题,只经过困难值小于等于x的路径,容易想到用Kruskal重构树:又要查询第k高的山峰,我们选择用主席树求解. 先做一棵重构树,跑一遍dfs,重构树中每一个非叶子节点对应一段区间,我们开range[ ...

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

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

  4. 洛谷4719 【模板】动态dp 学习笔记(ddp 动态dp)

    qwq大概是混乱的一个题. 首先,还是从一个比较基础的想法开始想起. 如果每次暴力修改的话,那么每次就可以暴力树形dp 令\(dp[x][0/1]\)表示\(x\)的子树中,是否选择\(x\)这个点的 ...

  5. kruskal重构树学习笔记

    \(kruskal\) 重构树学习笔记 前言 \(8102IONCC\) 中考到了,本蒟蒻不会,所以学一下. 前置知识 \(kruskal​\) 求最小(大)生成树,树上求 \(lca​\). 算法详 ...

  6. P4197 Peaks [克鲁斯卡尔重构树 + 主席树][克鲁斯卡尔重构树学习笔记]

    Problem 在\(Bytemountains\)有\(n\)座山峰,每座山峰有他的高度\(h_i\) .有些山峰之间有双向道路相连,共\(M\)条路径,每条路径有一个困难值,这个值越大表示越难走, ...

  7. Kruskal重构树学习笔记+BZOJ3732 Network

    今天学了Kruskal重构树,似乎很有意思的样子~ 先看题面: BZOJ 题目大意:$n$ 个点 $m$ 条无向边的图,$k$ 个询问,每次询问从 $u$ 到 $v$ 的所有路径中,最长的边的最小值. ...

  8. 【学习笔记】Kruskal 重构树

    1. 例题引入:BZOJ3551 用一道例题引入:BZOJ3551 题目大意:有 \(N\) 座山峰,每座山峰有他的高度 \(h_i\).有些山峰之间有双向道路相连,共 \(M\) 条路径,每条路径有 ...

  9. 学习笔记:Kruscal 重构树

    网上感觉没有什么很详细 + 证明的讲解啊) 前置:Kruskal 求最小生成树. 这个算法可以将一棵树 / 无向连通图重构成一颗有性质的新树. 算法可以解决一些树上瓶颈边权之类的问题,可以把需要持久化 ...

随机推荐

  1. SVN版本冲突中 Files 的值“ < < < < < < < .mine”无效路径中具有非法字符的解决办法

    .NET 中 SVN版本冲突中 Files 的值“ < < < < < < < .mine”无效路径中具有非法字符的解决办法: 一. 1.将项目逐个进行编译, ...

  2. 06 Maven 聚合和继承

    Maven 聚合和继承 1. 聚合 2. 继承 <parent> <groupId>org.apache.karaf.demos</groupId> <art ...

  3. apicloud管理

    以下所有操作都是指“apicloud”平台下的管理: 1. 一定要记得备份证书.证书不是因为你记得别名和密码就能还原的.因为apicloud是服务器session存数据,千万不要打开多个app操作页面 ...

  4. IT 技术网站收集

    ## 脚本之家 http://www.jb51.net/ ## 菜鸟教程 http://www.runoob.com/ ## 编程中国 https://www.bccn.net/ ##

  5. 2018.06.30 BZOJ1857: [Scoi2010]传送带(三分套三分)

    1857: [Scoi2010]传送带 Time Limit: 1 Sec Memory Limit: 64 MB Description 在一个2维平面上有两条传送带,每一条传送带可以看成是一条线段 ...

  6. 2018.07.23 洛谷P4097 [HEOI2013]Segment(李超线段树)

    传送门 给出一个二维平面,给出若干根线段,求出x" role="presentation" style="position: relative;"&g ...

  7. ViewFlipper实现自动播放的图片库

    作者实现的基础上,加上了文字的变换 public class MainActivity extends Activity { private ViewFlipper viewFlipper; priv ...

  8. Python安装setuptools遇到的MARKER_EXPR错误

    # python setup.py install Traceback (most recent call last):   File "setup.py", line 11, i ...

  9. 《Forward团队-爬虫豆瓣top250项目-设计文档》

    成员:马壮,李志宇,刘子轩,年光宇,邢云淇,张良 设计方案: 1.能分析HTML语言: 2.提取重要数据,并保存为文本文档: 3.用PY代码调取文本文档的数据: 4.编写提取部分数据的python代码 ...

  10. day13(反射,BeanUtils包)

    反射, 获取字节码文件的方式: 方式一: 对象.getClass(); 方式二: 类名.Class; 方式三:   Class.forName(String Class); 通过字节码文件获取对象 定 ...