博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
洛谷P4197 Peaks&&克鲁斯卡尔重构树学习笔记(克鲁斯卡尔重构树+主席树)
阅读量:6223 次
发布时间:2019-06-21

本文共 3263 字,大约阅读时间需要 10 分钟。

 

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

据说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$大,所以还得套个主席树上树

然而就差不多了

1 //minamoto 2 #include
3 #include
4 #include
5 #include
6 using namespace std; 7 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++) 8 char buf[1<<21],*p1=buf,*p2=buf; 9 inline int read(){10 #define num ch-'0'11 char ch;bool flag=0;int res;12 while(!isdigit(ch=getc()))13 (ch=='-')&&(flag=true);14 for(res=num;isdigit(ch=getc());res=res*10+num);15 (flag)&&(res=-res);16 #undef num17 return res;18 }19 char sr[1<<21],z[20];int C=-1,Z;20 inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}21 inline void print(int x){22 if(C>1<<20)Ot();if(x<0)sr[++C]=45,x=-x;23 while(z[++Z]=x%10+48,x/=10);24 while(sr[++C]=z[Z],--Z);sr[++C]='\n';25 }26 const int N=2e5+5,M=N*16,K=5e5+5;27 struct node{28 int from,to,cost;29 node(){}30 node(int from,int to,int cost):from(from),to(to),cost(cost){}31 inline bool operator <(const node &b)const32 {
return cost
>1;49 if(x<=mid) R[now]=R[last],update(L[last],L[now],l,mid,x);50 else L[now]=L[last],update(R[last],R[now],mid+1,r,x);51 }52 int query(int a,int x,int k){53 int l=1,r=limit;54 for(int j=18;~j;--j)55 if(f[a][j]&&val[f[a][j]]<=x) a=f[a][j];56 int v=rt[rs[a]],u=rt[ls[a]-1];57 if(sum[v]-sum[u]
>1;60 if(tmp>=k) v=R[v],u=R[u],l=mid+1;61 else v=L[v],u=L[u],r=mid,k-=tmp;62 }63 return b[r];64 }65 void dfs(int u){66 mission(u),ls[u]=++num;67 if(u<=n) update(rt[num-1],rt[num],1,limit,h[u]);68 else rt[num]=rt[num-1];69 for(int i=head[u];i;i=Next[i]) dfs(ver[i]);70 rs[u]=num;71 }72 int main(){73 // freopen("testdata.in","r",stdin);74 n=read(),m=read(),q=read();75 bin[0]=1;for(int i=1;i<=22;++i) bin[i]=bin[i-1]<<1;76 for(int i=1;i<=2*n;++i) fa[i]=i;77 for(int i=1;i<=n;++i) b[i]=h[i]=read();78 for(int i=1,u,v,e;i<=m;++i)79 u=read(),v=read(),e=read(),E[i]=node(u,v,e);80 sort(b+1,b+1+n),limit=unique(b+1,b+1+n)-b-1;81 for(int i=1;i<=n;++i) h[i]=lower_bound(b+1,b+1+limit,h[i])-b;82 sort(E+1,E+1+m);dfn=n;83 for(int i=1;i<=m;++i){84 int u=find(E[i].from),v=find(E[i].to);85 if(u!=v){86 val[++dfn]=E[i].cost,fa[u]=fa[v]=dfn;87 add(dfn,u),add(dfn,v),f[u][0]=f[v][0]=dfn;88 if(dfn-n==n-1) break;89 }90 }91 for(int i=1;i<=dfn;++i) if(!ls[i]) dfs(find(i));92 while(q--){93 int v=read(),x=read(),k=read();94 print(query(v,x,k));95 }96 Ot();97 return 0;98 }

 

转载于:https://www.cnblogs.com/bztMinamoto/p/9680934.html

你可能感兴趣的文章
关于websocket
查看>>
Markdown语法备忘
查看>>
命令模式
查看>>
【观察】云栖大会厦门峰会:阿里云,这只“独角兽”是如何炼成的?
查看>>
交互设计师如何进行风险预判?
查看>>
遥感图像分类现状及存在的问题
查看>>
几行代码搞定java生成解析二维码功能
查看>>
关于领域驱动设计(DDD)中聚合设计的一些思考
查看>>
用Jersey构建RESTful服务4--通过jersey-client客户端调用Jersey的Web服务模拟CURD
查看>>
[js插件]学习Highcharts
查看>>
创建3层的服务模板 (2)--- App-V package 和 Application Profile
查看>>
基于java.nio.channels的编程实践-I
查看>>
多线程同步基础
查看>>
学习Nagios(一):Nagios安装
查看>>
@RequestParam 的用法
查看>>
修改CentOS菜单
查看>>
消息队列
查看>>
iOS开发UI篇—无限轮播(循环展示)
查看>>
iOS集成支付宝
查看>>
全栈工程师体能备战--阅读的书籍
查看>>