题目链接: 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. tcp/udp注意事项

  2. python之《tkinter》

    1.创建窗口 import tkinter as tk window = tk.Tk() window.title('my window') window.geometry('300x100') -- ...

  3. Python_字符串处理方法

    1.字符串转换 #strcpy(sStr1,sStr2) sStr1 = 'strcpy' sStr2 = sStr1 sStr1 = 'strcpy2' print sStr2 1.字符串复制 #s ...

  4. oss文件上传删除(批量删除)处理

    博主用的是阿里云的oss 首先先在阿里云下载安装sdk,相关的sdk下载请自行到阿里云下载 文档地址   https://help.aliyun.com/document_detail/85580.h ...

  5. MapReduce的工作流程

    MapReduce的工作流程 1.客户端将每个block块切片(逻辑切分),每个切片都对应一个map任务,默认一个block块对应一个切片和一个map任务,split包含的信息:分片的元数据信息,包含 ...

  6. 编译安装opssl

    wget http://www.openssl.org/source/openssl-1.0.1q.tar.gz tar zxvf openssl-1.0.1q cd openssl-1.0.1q . ...

  7. java工作两年了,连myBatis中的插件机制都玩不懂,那你工作危险了!

    插件的配置与使用 在mybatis-config.xml配置文件中配置plugin结点,比如配置一个自定义的日志插件LogInterceptor和一个开源的分页插件PageInterceptor: & ...

  8. centons 7 安装mysql

    1      CentOS 7 yum安装mysql 1.1    Yum 安装mysql CentOS用yum安装相对省事,省去很多配置环节 安装mysql 源 yum localinstall h ...

  9. Linux 设置静态路由表

    一般来说多半不会使用到这个操作,但是最近有几台服务器需要多网卡,一个内网一个外网.导致网络访问内网有时候不通,这就需要我们手动写一下路由表了.操作如: 创建配置文件 网卡配置路径:/etc/sysco ...

  10. Spring beanDefinition载入

    @Override public void refresh() throws BeansException, IllegalStateException { synchronized (this.st ...