链接

https://loj.ac/problem/2718

思路

我们希望x所在的连通块尽量的大,而且尽量走高处

离线的话可以询问排序,kruskal过程中更新答案

在线就要用kruskal重构树

这kruskal重构树的话,看图就明白了

叶子节点都是原树节点

非叶子节点都是边

按照从大到小的顺序依次加边(是深度不是长度)

如果连通块已经在一起就不联通,其他两个最大节点和这个边(新建节点)连边

看图就是很明白



我们发现,重构树的根到任意节点是单调的,也就是说,这是个二叉堆啊

那两点间联通的最小需要深度就是lca(x,y)这条边的深度

询问就是s这个点最远能向上跳到的最远点的子树答案

可能我讲的听不懂,那就看图自己想想吧

复杂度最多一个log

大体流程

多组数据,进入solve

dij预处理dis

kruskal利用并查集重构出树来

lca树剖预处理重构树

再dfs统计子树ans

之后在线查询lca

输出lca这个点的ans

细节

并查集最好优化下,因为他重构出来的树很容易感觉成哈夫曼树的形状

并查集按秩合并和随机rand时间差别不大

树剖链外跳,链内二分

错误

写了比较慢、、(不过一遍60TLE还是很嗨的)

错误只有一个,dij的堆忘记了默认大顶堆,导致复杂度不对,T死了

代码

/*
大体流程:
多组数据,进入solve
dij预处理dis
kruskal重构出树来
lca树剖预处理重构树(其实就是二分)
再dfs统计子树ans
之后在线查询
*/
#include <iostream>
#include <ctime>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <queue>
#include <utility>
#include <algorithm>
using namespace std;
const int N=1e6+7;
int read() {
int x=0,f=1;char s=getchar();
for(;s>'9'||s<'0';s=getchar()) if(s=='-') f=-1;
for(;s>='0'&&s<='9';s=getchar()) x=x*10+s-'0';
return x*f;
}
int n,m,rt;
int dis[N],w[N<<1],dsr[N<<1];
struct node {
int u,v,l,a;
bool operator < (const node &b) const {
return a>b.a;
}
} edge[N];
struct noi_2018_t1 {
int v,nxt;
} e[N<<1];
int head[N<<1],add_tot;
void add(int u,int v) {
// cout<<u<<" "<<v<<"\n";
e[++add_tot].v=v;
e[add_tot].nxt=head[u];
head[u]=add_tot;
}
namespace bcj {
int fa[N<<1],siz[N<<1],id[N<<1];
int find(int x) {
return fa[x]==x ? x : fa[x]=find(fa[x]);
}
void uu(int fx,int fy) {
fx=find(fx),fy=find(fy);
id[fx]=id[fy]=max(id[fx],id[fy]);
if(siz[fx]<=siz[fy]) {
fa[fx]=fy;
if(siz[fx]==siz[fy]) siz[fy]++;
} else {
fa[fy]=fx;
}
}
}
namespace get_lca {
int fa[N<<1],top[N<<1],siz[N<<1],son[N<<1],dep[N<<1],idx[N<<1],js,frm[N<<1];
void dfs1(int u,int f) {
dep[u]=dep[f]+1;
fa[u]=f;
siz[u]=1;
for(int i=head[u];i;i=e[i].nxt) {
int v=e[i].v;
dfs1(v,u);
siz[u]+=siz[v];
if(siz[son[u]]<siz[v]) son[u]=v;
}
}
void dfs2(int u,int topf) {
top[u]=topf;
idx[u]=++js;
frm[js]=u;
if(!son[u]) return;
dfs2(son[u],topf);
for(int i=head[u];i;i=e[i].nxt) {
int v=e[i].v;
if(!idx[v]) dfs2(v,v);
}
}
int lca(int x,int val) {
int ans=x;
while(w[top[x]]>val) ans=top[x],x=fa[top[x]];
int l=idx[top[x]],r=idx[x];
while(l<=r) {
// cout<<l<<" "<<r<<"\n";
int mid=(l+r)>>1;
if(w[frm[mid]]>val) ans=frm[mid],r=mid-1;
else l=mid+1;
}
return ans;
}
void init() {
dfs1(rt,0);
dfs2(rt,rt);
}
}
namespace dij {
struct node {
int v,nxt,q;
}e[N<<1];
int head[N<<1],tot;
void add(int u,int v,int q) {
e[++tot].v=v;
e[tot].q=q;
e[tot].nxt=head[u];
head[u]=tot;
}
void dij() {
priority_queue<pair<int,int> > q;
q.push(make_pair(0,1));
dis[1]=0;
while(!q.empty()) {
pair<int,int> u=q.top();
q.pop();
if(dis[u.second]!=-u.first) continue;
for(int i=head[u.second];i;i=e[i].nxt) {
int v=e[i].v;
if(dis[v]>dis[u.second]+e[i].q) {
dis[v]=dis[u.second]+e[i].q;
q.push(make_pair(-dis[v],v));
}
}
}
}
void work() {
memset(dis,0x3f,sizeof(dis));
memset(head,0,sizeof(head));
tot=0;
for(int i=1;i<=m;++i) {
add(edge[i].u,edge[i].v,edge[i].l);
add(edge[i].v,edge[i].u,edge[i].l);
}
dij();
}
}
namespace kruskal {
void work() {
for(int i=1;i<n+n;++i) bcj::fa[i]=i;
for(int i=1;i<n+n;++i) bcj::id[i]=i;
sort(edge+1,edge+1+m);
for(int i=1;i<=n;++i) w[i]=0x3f3f3f3f;
for(int i=1,js=n;i<=m;++i) {
int fx=bcj::find(edge[i].u),fy=bcj::find(edge[i].v);
if(fx!=fy) {
rt=++js;
add(js,bcj::id[fx]),add(js,bcj::id[fy]);
w[js]=edge[i].a;
bcj::uu(js,fy);
bcj::uu(js,fx);
if(js==n+n-1) return;
}
}
}
}
void clear() {
add_tot=0;
dij::tot=0;
get_lca::js=0;
memset(dij::head,0,sizeof(dij::head));
memset(get_lca::siz,0,sizeof(get_lca::siz));
memset(bcj::siz,0,sizeof(bcj::siz));
memset(head,0,sizeof(head));
memset(dis,0x3f,sizeof(dis));
memset(get_lca::idx,0,sizeof(get_lca::idx));
memset(get_lca::son,0,sizeof(get_lca::son));
}
void dfs(int u,int f) {
dsr[u]=dis[u];
for(int i=head[u];i;i=e[i].nxt) {
int v=e[i].v;
dfs(v,u);
dsr[u]=min(dsr[u],dsr[v]);
}
}
void solve() {
dij::work();
// cout<<"1\n";
kruskal::work();
// cout<<"2\n";
get_lca::init();
// cout<<"3\n";
dfs(rt,0);
int Q=read(),k=read();
int S=read(),lastans=0;
while(Q--) {
int vv=read(),pp=read();
int v=(vv+k*lastans-1)%n+1;
int p=(pp+k*lastans)%(S+1);
int tmp=get_lca::lca(v,p);
lastans=dsr[tmp];
printf("%d\n",lastans);
}
}
int main() {
freopen("return.in","r",stdin);
freopen("return.out","w",stdout);
int T=read();
while(T--) {
n=read(),m=read();
for(int i=1;i<=m;++i) {
edge[i].u=read(),edge[i].v=read();
edge[i].l=read(),edge[i].a=read();
}
clear();
solve();
}
return 0;
}

#2718. 「NOI2018」归程 kruskal重构树的更多相关文章

  1. loj2718 「NOI2018」归程[Kruskal重构树+最短路]

    关于Kruskal重构树可以翻阅本人的最小生成树笔记. 这题明显裸的Kruskal重构树. 然后这题限制$\le p$的边不能走,实际上就是要满足走最小边权最大的瓶颈路,于是跑最大生成树,构建Krus ...

  2. loj#2718. 「NOI2018」归程

    题目链接 loj#2718. 「NOI2018」归程 题解 按照高度做克鲁斯卡尔重构树 那么对于询问倍增找到当前点能到达的高度最小可行点,该点的子树就是能到达的联通快,维护子树中到1节点的最短距离 s ...

  3. LOJ #2718. 「NOI2018」归程(Dijkstra + Kruskal重构树 + 倍增)

    题意 给你一个无向图,其中每条边有两个值 \(l, a\) 代表一条边的长度和海拔. 其中有 \(q\) 次询问(强制在线),每次询问给你两个参数 \(v, p\) ,表示在 \(v\) 出发,能开车 ...

  4. 洛谷 4768 LOJ 2718「NOI2018」归程

    [题解] 本题有多种做法,例如可持久化并查集.kruskal重构树等. kruskal重构树的做法是这样的:先把边按照海拔h从大到小的顺序排序,然后跑kruskal建立海拔的最大生成树,顺便建krus ...

  5. LOJ #2718. 「NOI2018」归程 Dijkstra+可持久化并查集

    把 $Noi2018$ day1t1 想出来还是挺开心的,虽然是一道水题~ 预处理出来 1 号点到其它点的最短路,然后预处理边权从大到小排序后加入前 $i$ 个边的并查集. 这个并查集用可持久化线段树 ...

  6. 「NOI2018」归程

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

  7. NOI Day1T1归程(Kruskal重构树+Dijkstra)

    NOI Day1T1归程(Kruskal重构树+Dijkstra) 题目 洛谷题目传送门 题解 其实我不想写......,所以...... 挖个坑......我以后一定会补的 luogu的题解讲的还是 ...

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

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

  9. [NOI2018]归程 kruskal重构树

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

随机推荐

  1. windows系统快捷键

    1.我的键盘:windows键的开启,需要按住FN键+windows键. 2.windows键 + E,表示打开我的电脑. 3.windows键 + R,打开windows的命令行窗口. 4.wind ...

  2. 2-1:math库与random库

    一.math库: math库是python语言中常用的一个函数库,它包含了一批数学函数,下面我们看一下这个函数库 由于math库中的函数与数学中的函数比较一致,相对比较简单,请同学们自行练习一下: 二 ...

  3. html5-样式表的使用-初步

    <!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8&qu ...

  4. BufferReader BufferWriter

    Copying information from one file to another with 'BufferReader BufferWriter' public class Demo5 { p ...

  5. python字典的排序,按key排序和按value排序---sorted()

    >>> d{'a': 5, 'c': 3, 'b': 4} >>> d.items()[('a', 5), ('c', 3), ('b', 4)] 字典的元素是成键 ...

  6. 禁用HTTP.sys,导致80端口被禁用和IIS服务无法启动解决办法

    由于端口被占用,使用 win+r 运行 cmd 输入netstat -ano 可以看到端口被PIF 4占用,可以找到对应的进程NT kernel& System 该进程是Http.sys,是h ...

  7. Git HEAD detached from XXX (git HEAD 游离) 解决办法

    本文 Git 图片主要来自:图解 Git,非常感谢! 读完本文你将了解: 什么是 HEAD HEAD 游离状态的利与弊 具体解决操作 Thanks 什么是 HEAD Git 中的 HEAD 可以理解为 ...

  8. jumpserver堡垒机安装

    1. 下载jumpserver cd /opt wget https://github.com/jumpserver/jumpserver/archive/master.zip unzip maste ...

  9. GoldenGate 12.3 MA架构介绍系列(4)–Restful API介绍

    OGG 12.3 MA中最大的变化就是使用了restful api,在前面介绍的各个服务模块,其实就是引用restful api开发而来,这些API同时也提供对外的集成接口,详细接口可参考: http ...

  10. mysql引擎和事务

    对于应用程序和用户来说,同样一张表的数据无论用什么引擎来存储,看到的数据都是一样的,只是不同的引擎在功能.占用空间大小.读取性能等方面可能有所差别. mysql最常用的存储引擎为Innodb.MyIS ...