题目链接: UOJ LOJ

感觉 Kruskal 重构树比较简单,就不单独开学习笔记了。

Statement

给定一个 \(n\) 点 \(m\) 边的无向连通图,用 \(l,a\) 描述一条边的长度、海拔。用水位线描述降雨,所有海拔不超过水位线的边都是有积水的。

有 \(q\) 次询问,每次给出出发点 \(v\) 和水位线 \(p\) ,开始会有一辆车,可以经过任意没有积水的边,可以在任意节点下车步行(车不会延续到下一次)。问回到 \(1\) 号点最小的步行长度。强制在线。

\(n\leq 2e5,m\leq 4e5,q\leq 4e5,1\leq S\leq 1e9,l\leq 1e4,a\leq 1e9\) .

Solution

名字挺高级的,事实上很简单。

重点解决的主要问题: 查询从某个点出发经过边权不超过 val 的边所能到达的节点

大致就是类似 点分治=>点分树 的思路,点分树是把点分治中所有分治重心按照层次关系连接起来形成树状结构,那么 Kruskal 重构树就是在 Kruskal 建最小生成树的时候,不直接合并两个点,而是新建一个虚点进行合并。好吧,看上去一点都不像

具体一点就看 这个博客 .

性质:一个点的所有子树节点的权值都不大于它的权值,并且从它开始逐渐向子节点移动,权值是单调不增的。

Proof

显然,考虑 Kruskal 的加边过程即可。

查询的时候进行树上倍增,得到能够到达的最远祖先,那么根据限制,能到达的连通块中的节点就是这个祖先点的子树中所有的叶节点。(除了叶节点都是虚点嘛)


回到这道题目。题目要求就是要将一条 \(v\to 1\) 的路径分成两部分,设断点为 \(u\) ,要满足 \(u\to v\) 的路径上所有边的海拔大于 \(p\) ,在此前提下 \(1\to u\) 最短。

那么很容易发现,合法 \(u\) 构成的点集在原图的最大生成树上。

根据上面的铺垫,容易想到使用 Kruskal 重构树:

把每条边按照海拔降序,求出重构树。按照上面的步骤,对于每个询问,树上倍增得到包含起点 \(v\) 的子树中根节点深度最小且海拔大于 \(p\) 的子树 \(x\) ,那么合法 \(u\) 的集合就是 \(x\) 子树内的所有叶子节点。现在就要在这些点中找出到点 \(1\) 的最短路。这个同样可以在 Kruskal 中求解出路径,并在每个节点统计子树内的最短路径长度即可,复杂度是 \(\mathcal{O}(1)\) 的。

总复杂度为 \(\mathcal{O}(T\times n\log n)\) .

Code

过不去 UOJ Extra Test 的多半是没开 long long.

//Author: RingweEH
const int N=2e5+10;
struct edge
{
int to,nxt,val;
}e[N<<2];
struct node
{
int u; ll dis;
bool operator < ( const node &tmp ) const { return dis>tmp.dis; }
};
struct edge2
{
int fro,to,val;
bool operator < ( const edge2 &tmp ) const { return val>tmp.val; }
}e2[N<<1];
int n,m,q,k,s,tot=0,head[N],fath[N<<1],fa[N<<1][21],a[N<<1],siz;
ll dis[N<<1],lasans; void add( int u,int v,int w )
{
e[++tot].to=v; e[tot].nxt=head[u]; head[u]=tot; e[tot].val=w;
} void Dijkstra()
{
priority_queue<node> q;
for ( int i=1; i<=n*2-1; i++ )
dis[i]=1e15;
dis[1]=0; q.push( (node){1,0} );
while ( !q.empty() )
{
node u=q.top(); q.pop();
if ( u.dis>dis[u.u] ) continue;
for ( int i=head[u.u]; i; i=e[i].nxt )
if ( u.dis+e[i].val<dis[e[i].to] ) q.push( (node){e[i].to,dis[e[i].to]=u.dis+e[i].val} );
}
} int find( int x )
{
return x==fath[x] ? x : fath[x]=find(fath[x]);
} void Kruskal()
{
memset( fa,0,sizeof(fa) ); siz=n;
for ( int i=1; i<n*2; i++ )
fath[i]=i;
sort( e2+1,e2+1+m );
for ( int i=1; i<=m; i++ )
{
int u=find( e2[i].fro ),v=find( e2[i].to );
if ( u==v ) continue;
fa[u][0]=fath[u]=fa[v][0]=fath[v]=++siz;
a[siz]=e2[i].val; dis[siz]=min( dis[u],dis[v] );
if ( siz==n*2-1 ) break;
}
for ( int i=siz; i>=1; i-- )
for ( int j=1; j<=18; j++ )
fa[i][j]=fa[fa[i][j-1]][j-1];
} int main()
{
freopen( "return.in","r",stdin ); freopen( "return.out","w",stdout ); int T=read();
while ( T-- )
{
memset( head,0,sizeof(head) ); tot=lasans=0; n=read(); m=read();
for ( int i=1; i<=m; i++ )
{
e2[i].fro=read(),e2[i].to=read(); int w=read(); e2[i].val=read();
add( e2[i].fro,e2[i].to,w ); add( e2[i].to,e2[i].fro,w );
}
q=read(); k=read(); s=read(); Dijkstra(); Kruskal();
while ( q-- )
{
int v=read(),p=read();
v=(v+k*lasans-1)%n+1; p=(p+k*lasans)%(s+1);
for ( int i=17; i>=0; i-- )
if ( fa[v][i] && a[fa[v][i]]>p ) v=fa[v][i];
printf( "%lld\n",dis[v] ); lasans=dis[v];
}
} fclose( stdin ); fclose( stdout );
return 0;
}

Kruskal重构树——[NOI2018] 归程的更多相关文章

  1. [NOI2018]归程 kruskal重构树

    [NOI2018]归程 LG传送门 kruskal重构树模板题. 另一篇文章里有关于kruskal重构树更详细的介绍和更板子的题目. 题意懒得说了,这题的关键在于快速找出从查询的点出发能到达的点(即经 ...

  2. [洛谷P4768] [NOI2018]归程 (kruskal重构树模板讲解)

    洛谷题目链接:[NOI2018]归程 因为题面复制过来有点炸格式,所以要看题目就点一下链接吧\(qwq\) 题意: 在一张无向图上,每一条边都有一个长度和海拔高度,小\(Y\)的家在\(1\)节点,并 ...

  3. [luogu4768] [NOI2018] 归程 (Dijkstra+Kruskal重构树)

    [luogu4768] [NOI2018] 归程 (Dijkstra+Kruskal重构树) 题面 题面较长,这里就不贴了 分析 看到不能经过有积水的边,即不能经过边权小于一定值的边,我们想到了kru ...

  4. Luogu P4768 [NOI2018]归程(Dijkstra+Kruskal重构树)

    P4768 [NOI2018]归程 题面 题目描述 本题的故事发生在魔力之都,在这里我们将为你介绍一些必要的设定. 魔力之都可以抽象成一个 \(n\) 个节点. \(m\) 条边的无向连通图(节点的编 ...

  5. P4768 [NOI2018]归程(kruskal 重构树)

    洛谷P4768 [NOI2018]归程 LOJ#2718.「NOI2018」归程 用到 kruskal 重构树,所以先说这是个啥 显然,这和 kruskal 算法有关系 (废话 这个重构树是一个有点权 ...

  6. BZOJ5415[Noi2018]归程——kruskal重构树+倍增+堆优化dijkstra

    题目描述 本题的故事发生在魔力之都,在这里我们将为你介绍一些必要的设定. 魔力之都可以抽象成一个 n 个节点.m 条边的无向连通图(节点的编号从 1 至 n).我们依次用 l,a 描述一条边的长度.海 ...

  7. 2018.07.18 [NOI2018]归程(return)(kruskal重构树)

    传送门 新鲜出炉的noi2018试题. 下面讲讲这题的解法: 首先要学习一个叫做kruskal重构树的东东. 听名字就知道跟kruskal算法有关,没错,原来的kruskal算法就是用并查集实现的,但 ...

  8. NOI2018归程(Kruskal重构树)

    题目描述 本题的故事发生在魔力之都,在这里我们将为你介绍一些必要的设定. 魔力之都可以抽象成一个 n 个节点.m 条边的无向连通图(节点的编号从 1 至 n). 我们依次用 l,a 描述一条边的长度. ...

  9. BZOJ 5415: [Noi2018]归程(kruskal重构树)

    解题思路 \(NOI2018\)的\(Day1\) \(T1\),当时打网络赛的时候不会做.学了一下\(kruskal\)重构树后发现问题迎刃而解了.根据\(kruskal\)的性质,如果要找从\(u ...

随机推荐

  1. 位图bitmap应用

    所有比特的编号方法是,从低字节的低位比特位开始,第一个bit为0,最后一个bit为 n-1. 比如说,现在有个数组是这样子的,int a[4],那么a[0]的比特位为0--31a[1]的比特位为32- ...

  2. POSIX条件变量

    条件变量: 当一个线程互斥的访问某个变量时,它可能发现其他线程改变状态之前,它什么都做不了例如:一个线程访问队列时,发现队列为空,它只能等待,直到其他线程将一个节点添加到队列中,这种情况就需要使用条件 ...

  3. 创建Grafana监控视图

    前言 Grafana允许查询,可视化,警报和了解指标,无论它们存储在哪里. 可视化:具有多种选项的快速灵活的客户端图.面板插件提供了许多不同的方式来可视化指标和日志. 动态仪表盘:使用模板变量创建动态 ...

  4. 关闭防火墙和设置主机名和ip及克隆机网卡处理方法

    关闭防火墙: service NetworkManager stop --图形化用ifconfig之前先关掉网络服务. chkconfig NetworkManager off (将开机自启动关掉,使 ...

  5. CephFS用户认证格式写错的问题

    问题三: CephFS(James Gallagher) 问题原文 Hi, I'm looking to implement the CephFS on my Firefly release (v0. ...

  6. HTTP介绍(一)

    超文本传输协议(HTTP)是一种用于分布式,协作式超媒体信息系统的应用程序层协议.HTTP是万维网(World Wide Web)数据通信的基础,超文本文档包括指向用户可以轻松访问的其他资源的超链接, ...

  7. 2018.1.15复习_ css+js

    [1]几个常见的css标签:--------------------------------------------------background-color; 设置背景颜色background-p ...

  8. HDU100题简要题解(2040~2049)

    HDU2040 亲和数 题目链接 Problem Description 古希腊数学家毕达哥拉斯在自然数研究中发现,220的所有真约数(即不是自身的约数)之和为: 1+2+4+5+10+11+20+2 ...

  9. [原题复现+审计][BUUCTF 2018]WEB Online Tool(escapeshellarg和escapeshellcmd使用不当导致rce)

    简介  原题复现:https://github.com/glzjin/buuctf_2018_online_tool (环境php5.6.40)  考察知识点:escapeshellarg和escap ...

  10. 算法基础——KMP字符串匹配

    原题链接 题目: 给定一个模式串S,以及一个模板串P,所有字符串中只包含大小写英文字母以及阿拉伯数字. 模板串P在模式串S中多次作为子串出现. 求出模板串P在模式串S中所有出现的位置的起始下标. 输入 ...