题意:给一张无向联通图,每条边有长度和高度,每次询问在高度大于p的边,从v点能到达的所有点到1号点的最短距离(强制在线)

首先dijkstra求出每个点到1号点的距离

易知:如果我按高度从高到低给边排序然后用kruskal的方法做出一棵生成树,那么在高度大于p的条件下,在原图中联通的两点在生成树中依旧联通

于是就可以在做kruskal的时候建一个叫做重构树的东西,在用并查集维护联通块的同时维护一个树结构:

  对于每条边,若原本两端点u,v不连通,则新建一个节点t,设a,b为u,v在并查集中的祖先,令并查集和树结构中fa[a]=fa[b]=t,同时记下树中t的两个孩子为a,b,以及t的高度与边的高度相同

这样,树中的每棵子树的叶节点都是连通的,并且树中深度越深,节点对应边的高度就越大

dfs一下就可以处理出每个子树对应联通块的距1号点的最近距离。

然后对于点v,就可以倍增找出高度恰大于p的那个节点,就是最后结果

 #include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
#define LL long long int
#define pa pair<int,int>
using namespace std;
const int maxn=2e5+,logn=,maxm=4e5+,inf=0x3f3f3f3f; int rd(){
int x=;char c=getchar();
while(c<''||c>'') c=getchar();
while(c>=''&&c<='') x=x*+c-'',c=getchar();
return x;
} struct Edge{
int a,b,l,h,ne;
}eg[maxm*];
struct Node{
int fa[logn],v,h,ch[];
}tr[maxn*];
int bcj[maxn*],tct;
int N,M,Q,K,S;
int egh[maxn],ect;
int dis[maxn];
priority_queue<pa,vector<pa>,greater<pa> > q; inline void adeg(int a,int b,int l,int h){
eg[ect].a=a;eg[ect].b=b;eg[ect].l=l;eg[ect].h=h;eg[ect].ne=egh[a];egh[a]=ect++;
} void dijkstra(){
memset(dis,,sizeof(dis));dis[]=;
q.push(make_pair(,));
while(!q.empty()){
int p=q.top().second;q.pop();
for(int i=egh[p];i!=-;i=eg[i].ne){
int b=eg[i].b;
if(dis[b]>dis[p]+eg[i].l){
dis[b]=dis[p]+eg[i].l;
q.push(make_pair(dis[b],b));
}
}
}
} int getf(int x){return x==bcj[x]?x:bcj[x]=getf(bcj[x]);} void kruskal(){
memset(tr,,sizeof(tr));
for(int i=;i<=N*;i++) bcj[i]=i,tr[i].v=inf;tct=N;
for(int i=,n=;i<ect&&n<N;i++){
int a=getf(eg[i].a),b=getf(eg[i].b);
if(a==b) continue;
bcj[a]=bcj[b]=++tct;
tr[a].fa[]=tr[b].fa[]=tct;
tr[tct].ch[]=a;tr[tct].ch[]=b;
tr[tct].h=eg[i].h;n++;
}
} void dfs(int x){
for(int i=;i<logn-;i++){
if(!tr[tr[x].fa[i]].fa[i]) break;
tr[x].fa[i+]=tr[tr[x].fa[i]].fa[i];
}
if(tr[x].ch[]){
dfs(tr[x].ch[]);dfs(tr[x].ch[]);
tr[x].v=min(tr[tr[x].ch[]].v,tr[tr[x].ch[]].v);
}else tr[x].v=dis[x];
} inline bool cmp(Edge a,Edge b){
return a.h>b.h;
} int query(int v,int p){
for(int i=logn-;i>=;i--){
if(tr[v].fa[i]&&tr[tr[v].fa[i]].h>p) v=tr[v].fa[i];
}return tr[v].v;
} int main(){
int i,j,k;
//freopen("return.in","r",stdin);
for(int T=rd();T;T--){
N=rd(),M=rd();memset(egh,-,sizeof(egh));ect=;
for(i=;i<=M;i++){
int a=rd(),b=rd(),c=rd(),d=rd();
adeg(a,b,c,d);adeg(b,a,c,d);
}dijkstra();
sort(eg,eg+ect,cmp);kruskal();dfs(tct);
Q=rd(),K=rd(),S=rd();
int lastans=;
for(i=;i<=Q;i++){
int v=(rd()+K*lastans-)%N+;
int p=(rd()+K*lastans)%(S+);
printf("%d\n",lastans=query(v,p));
}
}
}

NOI2018d1t1 归程 (dijkstra+kruskal重构树)的更多相关文章

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

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

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

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

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

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

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

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

  5. NOI2018归程(Kruskal重构树)

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

  6. 「NOI 2018」归程「Kruskal 重构树」

    题解 Kruskal重构树:每次一条边连接两个集合,建一个新点,点权为该边边权:把这两个集合的根连向新点. 性质:(如果求的是最大生成树)叶子结点是图中实际结点:叶子到根路径上点权递减:两点间lca的 ...

  7. 【BZOJ5415&UOJ393】归程(Kruskal重构树,最短路)

    题意:From https://www.cnblogs.com/Memory-of-winter/p/11628351.html 思路:先从1开始跑一遍dijkstra,建出kruskal重构树之后每 ...

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

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

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

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

随机推荐

  1. apply和call方法

    真伪数组转换 /* apply和call方法的作用: 专门用于修改方法内部的this 格式: call(对象, 参数1, 参数2, ...); apply(对象, [数组]); */ function ...

  2. oracle导出用户下单表或者多表,导入到别的服务器用户下

      导出   exp 用户名/密码 file=存放dmp的名称的目录 statistics=none tables =(表名,表名,表名) exp creditfw/credit file=d:\te ...

  3. java依赖的斗争:依赖倒置、控制反转和依赖注入

    控制反转(Inversion Of Controller)的一个著名的同义原则是由Robert C.Martin提出的依赖倒置原则(Dependency Inversion Principle),它的 ...

  4. Laravel中resource方法

    新增的 resource 方法将遵从 RESTful 架构为用户资源生成路由.该方法接收两个参数,第一个参数为资源名称,第二个参数为控制器名称. Route::resource('users', 'U ...

  5. Laravel 门面实例教程 —— 创建自定义 Facades 类

    我们首先创建一个需要绑定到服务容器的Test类: <?php namespace App\Facades; class Test { public function doSomething() ...

  6. 头文件带和不带.h的区别

    所有C++标准库的头文件都是没有.h结尾的.这么做是为了区分,C标准库的头文件和C++标准库的头文件.比如最具代表性的: #include <string.h> // C 标准库头文件,包 ...

  7. 查看端口占用cmd命令

    查看端口被占用的进程: 在任务管理器中结束进程:

  8. PHP二维数组(或任意维数组)转换成一维数组的方法汇总(实用)

    目录 1 array_reduce函数法 2 array_walk_recursive函数法 3 array_map函数法 假设有下面一个二维数组: $user = array( '0' => ...

  9. CLOUD设置过滤方案不共享

    1.打开BOS,找到应用框架-动态表单-过滤方案另存 2.找到共享给他人,把可见性全部去掉

  10. springMVC中@RequestParam和@RequestBody的作用

    @RequestParam和@RequestBody是什么区别,估计很多人还是不太清楚, 因为一般用@ RequestParam就足够传入参数了,要说他们区别,就需要知道contentType是什么? ...