这道题最后会化为这么一个问题:给一张图,每条边都有边权,多组询问,每次给出 u , k u,k u,k,问从 u u u 开始走,只走边权 ≤ k \leq k ≤k 的边,请维护 u u u 能走到的点的集合。

这就需要用到一种叫 kruskal 重构树的东东。

首先可以发现,若 u u u 能走到 v v v,那么 u u u 在最小生成树上也必然能走到 v v v,所以我们只需要在原图的最小生成树上面走即可。

我们考虑用 kruskal 算法构建最小生成树时的过程:假设当前枚举到的边的两个端点所在连通块不同(设这两个连通块的根分别是 a , b a,b a,b),那么我们就新建立一个虚点 c c c,令 c c c 为 a , b a,b a,b 的父亲,令 c c c 的点权为这条边的边权。这也就是相当于把构建并查集的过程给描述出来。

这样建出来的树有许多很好的性质:

  • 这是一棵完全二叉树。

  • 树上的每一个叶子节点对应着最小生成树上的点(即原图的点),每一个非叶子节点对应着最小生成树上的边。

  • 父亲节点的点权大于等于儿子节点的点权(儿子节点非叶子节点),于是这也是一个二叉堆。

  • 两点 u , v u,v u,v 的 l c a lca lca 的点权即为最小生成树上 u u u 到 v v v 路径上的最大边权,但注意两点 u , v u,v u,v 在 kruskal 重构树上的路径所经过的所有非叶子节点所代表的边并不是 u , v u,v u,v 在最小生成树上的路径所经过的边。

    对于某个非叶子节点 u u u,若 u u u 的权值严格小于其父亲的权值(加上这个条件是因为有相同边权的存在),那么 u u u 的子树内的所有叶子节点所代表的点就是最小生成树上从 u u u 所代表的的边 e e e 出发、不经过权值比 e e e 大的边所能到达的所有点。

  • ……

那么我们可以先把 kruskal 重构树建出来,然后每次询问时用倍增找到 u u u 的最远的权值小于等于 k k k 的祖先 f f f,那么 f f f 子树内的所有叶子节点即为最小生成树上 u u u 能到达的所有点。

整题的代码如下:

#include<bits/stdc++.h>#define LN 19
#define N 200010
#define M 400010
#define lc(u) ch[u][0]
#define rc(u) ch[u][1]using namespace std;inline int read()
{int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^'0');ch=getchar();}return x*f;
}struct Edge
{int u,v,w;Edge(){};Edge(int a,int b,int c){u=a,v=b,w=c;}
}e[M];bool operator < (Edge a,Edge b)
{return a.w>b.w;
}struct data
{int u,s;data(){};data(int a,int b){u=a,s=b;}bool operator < (const data &a) const{return s>a.s;}
};int t,n,m,Q,k,s;
int cnt,head[N],nxt[M<<1],to[M<<1],w[M<<1];
int dis[N];
int rt,node,ch[N<<1][2];
int d[N<<1],fa[N<<1][LN],val[N<<1],minn[N<<1];
int f[N<<1];
bool vis[N];priority_queue<data>q;void adde(int u,int v,int wi)
{to[++cnt]=v;w[cnt]=wi;nxt[cnt]=head[u];head[u]=cnt;
}void dijkstra()
{memset(vis,0,sizeof(vis));memset(dis,127,sizeof(dis));dis[1]=0;q.push(data(1,0));while(!q.empty()){data now=q.top();q.pop();if(vis[now.u]) continue;vis[now.u]=1;for(int i=head[now.u];i;i=nxt[i]){int v=to[i];if(dis[now.u]+w[i]<dis[v]){dis[v]=dis[now.u]+w[i];q.push(data(v,dis[v]));}}}
}int find(int x)
{return x==f[x]?x:(f[x]=find(f[x]));
}void dfs(int u)
{for(int i=1;i<=18;i++)fa[u][i]=fa[fa[u][i-1]][i-1];if(!lc(u)&&!rc(u)){minn[u]=dis[u];return;}fa[lc(u)][0]=fa[rc(u)][0]=u;dfs(lc(u)),dfs(rc(u));minn[u]=min(minn[lc(u)],minn[rc(u)]);
}int query(int u,int x)
{for(int i=18;i>=0;i--)if(fa[u][i]&&val[fa[u][i]]>x)u=fa[u][i];return minn[u];
}int main()
{t=read();while(t--){cnt=0;memset(head,0,sizeof(head));n=read(),m=read();for(int i=1;i<=m;i++){int u=read(),v=read(),l=read(),a=read();adde(u,v,l),adde(v,u,l);e[i]=Edge(u,v,a);}dijkstra();sort(e+1,e+m+1);for(int i=1;i<=n;i++) f[i]=i,lc(i)=rc(i)=0;node=n;for(int i=1,tot=0;tot<n-1;i++){int a=find(e[i].u),b=find(e[i].v);if(a!=b){node++;val[node]=e[i].w;f[a]=f[b]=f[node]=node;lc(node)=a,rc(node)=b;tot++;}}rt=node;fa[rt][0]=0,d[rt]=1;dfs(rt);Q=read(),k=read(),s=read();int lans=0;while(Q--){int u=read(),x=read();u=(u+k*lans-1)%n+1;x=(x+k*lans)%(s+1);printf("%d\n",lans=query(u,x));}}return 0;
}

【NOI2018】归程(kruskal重构树)相关推荐

  1. 洛谷P4768 [NOI2018]归程(Kruskal重构树)

    题意 直接看题目吧,不好描述 Sol 考虑暴力做法 首先预处理出从$1$到每个节点的最短路, 对于每次询问,暴力的从这个点BFS,从能走到的点里面取$min$ 考虑如何优化,这里要用到Kruskal重 ...

  2. LOJ.2718.[NOI2018]归程(Kruskal重构树 倍增)

    LOJ2718 BZOJ5415 洛谷P4768 Rank3+Rank1无压力 BZOJ最初还不是一道权限题... Update 2019.1.5 UOJ上被hack了....好像是纯一条链的数据过不 ...

  3. 洛谷 - P4768 [NOI2018]归程(Kruskal重构树+树上倍增+最短路)

    题目链接:点击查看 题目大意:去原网址看吧 题目分析:因为是在刷克鲁斯卡尔重构树的题目,所以稍微思考一下就能想出解法了,首先如果水位线固定了,剩下的边组成的最小生成树也是一定的,此时同一个连通块内的点 ...

  4. P4768 [NOI2018] 归程 Kruskal重构树 + 倍增 + 最短路

    传送门 文章目录 题意: 思路: 题意: 给你一个联通无向图,每条边有一个长度lll和海拔aaa,当海拔≤\le≤水位线的时候,说明这个道有积水.在起始点有一辆车,车可以走没有积水的路,下车后可以走有 ...

  5. NOI 2018 归程 (Kruskal重构树)

    题目大意:太长了,略 Kruskal重构树,很神奇的一个算法吧 如果两个并查集被某种条件合并,那么这个条件作为一个新的节点连接两个并查集 那么在接下来的提问中,如果某个点合法,它的所有子节点也都合法, ...

  6. [NOI2018] 归程(线段树维护并查集的可持久化/kruskal重构树,倍增+dijkstra最短路)

    [NOI2018] 归程 description solution1 code1 solution2 code description 题目描述 本题的故事发生在魔力之都,在这里我们将为你介绍一些必要 ...

  7. NOI2018 Day1 归程(Kruskal重构树)

    目录 NOI2018 Day1 return 题解 AC代码: NOI2018 Day1 return 题解 作为NOI Day1 的T1,这道题目还是比较清真的(虽然自己在同步赛的时候只打了70分的 ...

  8. NOI2018 D1T1 洛谷P4768 归程 (Kruskal重构树)

    题目传送门 实际上是一个最短路问题,但加上了海拔这个条件限制,要在海拔<水位线p中找最短路. 这里使用Kruskal重构树,将其按海拔建成小根堆,我们就可以在树中用倍增找出他不得不下车的点:树中 ...

  9. 【NOI 2018】归程(Kruskal重构树)

    题面在这里就不放了. 同步赛在做这个题的时候,心里有点纠结,很容易想到离线的做法,将边和询问一起按水位线排序,模拟水位下降,维护当前的各个联通块中距离$1$最近的距离,每次遇到询问时输出所在联通块的信 ...

最新文章

  1. Opencv2.4.4示例程序说明
  2. linux命令 iperf-网络性能测试工具
  3. Android涂鸦技术及刮刮乐示例分析
  4. MySQL(六)常用语法和数据类型
  5. 高中计算机计划,高中信息技术教学计划
  6. 关于Django中的数据库操作API之distinct去重的一个误传
  7. hive udaf_Hive自定义函数
  8. sip hold 解决方法【原创】
  9. 共享端口445能改吗_模玩控:高达模型改圣斗士星矢五小强,大家能认出它们都是机体吗?...
  10. SELinux 基础命令
  11. Win11想运行老游戏怎么设置
  12. STM32学习——直接存储器访问(DMA)
  13. 给孩子简单快乐的童年
  14. 空间计量 python_空间计量经济学与Stata实现
  15. 应用程序无法正常启动(0xc000007b)
  16. linux中swi指令,Arm Linux系统调用流程详细解析SWI
  17. MySQL 优化器原来是这样工作的
  18. 抖音、快手、百度等105款App 遭通报
  19. 关于路由器再接一个路由器(无线的也OK)方法【亲测可用】
  20. 用计算机录节目,如何在电脑上录制电视节目?高清稳定的录制方法分享

热门文章

  1. 解析json文件、执行批量修改sql
  2. 中秋节文案、海报 ||海上生明月,天涯共此时
  3. Greenshot 0.8.0-0627 stable version
  4. Spring Security和Angular教程(二)登录页面
  5. 字符串处理(C++)
  6. java jama matrix转数组_Java Jama矩阵问题
  7. Linux基础学习(Ubuntu)
  8. python之WEB登录密码暴力破解
  9. SAP HR技术系列之一:e-HR,不只是看起来很美
  10. 辞职一年不上班,生活会变得怎么样?