kruskal 重构树
对于一张无向图,我们在进行 kruskal 的过程中
每当合并两个联通块时
新建虚拟节点 t
对于两个联通块的根节点 fau,fav 连无向边
(fau, t),(fav, t) 其中点 t 的点权为两个联通块当前连边的边权
对于这道题
首先 dijkstra 处理所有点到1号点的最短路
然后按照边的海拔进行降序排序
这样做出重构树之后
显然对于点 u,它的所有子树中的相关的边的海拔(这里已经转化为了虚拟节点的点权)都要大于该点的海拔
这样的话
对于询问二元组 x, h
倍增将 x 调到海拔最低且高于 h 的点处
此时 x 的子树中dis[]的最小值即为此次询问的结果
注意:在进行重构树时
虚拟节点的dis[]每次可以取 min(dis[fau], dis[fav])
这样就相当于dis[t]表示 t 的子树中dis[]的最小值
省去了一遍 dfs

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <cstring> using namespace std;
const int N = 4e5 + , oo = 1e9 + ; struct Node {
int u, v, len, high, nxt;
} E[N], G[N << ], Edge[N << ];
struct Node_ {
int u, dis_;
inline bool operator < (const Node_ a) const {return dis_ > a.dis_;}
}; int head_1[N], head_2[N << ], now;
int dis[N << ];
bool vis[N];
int fa[N << ];
int n, m;
int High[N << ];
int f[N << ][];
int deep[N << ]; #define gc getchar()
inline int read() {
int x = ;
char c = gc;
while(c < '' || c > '') c = gc;
while(c >= '' && c <= '') x = x * + c - '', c = gc;
return x;
} int Get(int x) {return fa[x] == x ? x : fa[x] = Get(fa[x]);}
inline bool Cmp(Node a, Node b) {return a.high > b.high;}
void Dfs(int u, int fa) {for(int i = head_2[u]; ~ i; i = G[i].nxt) if(G[i].v != fa) f[G[i].v][] = u, Dfs(G[i].v, u);}
inline int Jump(int X, int H) {for(int i = ; i >= ; i --) if(f[X][i] && High[f[X][i]] > H) X = f[X][i];return X;}
inline void Add_Edge(int u, int v, int Len) {Edge[++ now].v = v; Edge[now].len = Len; Edge[now].nxt = head_1[u]; head_1[u] = now;}
inline void Add_G(int u, int v) {G[++ now].v = v; G[now].nxt = head_2[u]; head_2[u] = now;}
inline void Pre() {for(int i = ; i <= ; i ++) for(int j = ; j <= (n * - ); j ++) f[j][i] = f[f[j][i - ]][i - ];} inline void Dijkstra() {
for(int i = ; i <= n; i ++) dis[i] = oo;
for(int i = ; i <= n; i ++) vis[i] = ;
priority_queue <Node_> Q;
Q.push((Node_) {, });
dis[] = ;
while(!Q.empty()) {
Node_ topp = Q.top();
Q.pop();
if(vis[topp.u]) continue;
vis[topp.u] = ;
for(int i = head_1[topp.u]; ~ i; i = Edge[i].nxt)
if(dis[Edge[i].v] > dis[topp.u] + Edge[i].len) {
dis[Edge[i].v] = dis[topp.u] + Edge[i].len;
Q.push((Node_) {Edge[i].v, dis[Edge[i].v]});
}
}
} inline void Kruskal() {
sort(E + , E + m + , Cmp);
for(int i = ; i <= (n << ); i ++) fa[i] = i;
for(int i = ; i <= (n << ); i ++) head_2[i] = -;
int cnt = n;
now = ;
for(int i = ; i <= m; i ++) {
if(cnt == n * - ) break;
int u = E[i].u, v = E[i].v, fau = Get(u), fav = Get(v);
if(fau != fav) {
fa[fau] = fa[fav] = ++ cnt;
High[cnt] = E[i].high;
dis[cnt] = min(dis[fau], dis[fav]);
Add_G(fau, cnt), Add_G(cnt, fau), Add_G(fav, cnt), Add_G(cnt, fav);
}
}
} int main() {
for(int T = read(); T; T --) {
memset(f, , sizeof f);
n = read(), m = read(); now = ;
for(int i = ; i <= n; i ++) head_1[i] = -;
for(int i = ; i <= m; i ++) {
int u = read(), v = read(), Len = read(), high = read();
Add_Edge(u, v, Len), Add_Edge(v, u, Len);
E[i] = (Node) {u, v, Len, high};
}
Dijkstra(), Kruskal(), Dfs( * n - , ), Pre();
int Q = read(), K = read(), S = read(), Lastans = ;
for(; Q; Q --) {
int X = (read() + K * Lastans - ) % n + , H = (read() + K * Lastans) % (S + );
Lastans = dis[Jump(X, H)]; cout << Lastans << "\n";
}
}
return ;
}

最新文章

  1. [Python] 机器学习库资料汇总
  2. WebRTC源码分析四:视频模块结构
  3. 查看PHP的配置信息
  4. js调试技巧 Firefox调试技巧汇总
  5. python高级编程技巧
  6. SQL Server常用脚本
  7. Best Time to Buy and Sell Stock (java)
  8. CMake学习小结
  9. HDU2504 又见GCD
  10. 2017湖湘杯Writeup
  11. 2-学习GPRS_Air202(Air202开发板介绍和下载第一个程序)
  12. mysql数据备份及恢复
  13. C# winform使用combobox遍历文件夹内所有文件
  14. python中的optionParser模块
  15. python-获取当前工作路径
  16. vb.bet 控件
  17. 初学Java必写的小程序。
  18. [archlinux] 迁移T7从T460s到T470
  19. spring.schemas和spring.handlers对xmlns配置文件作用
  20. jqgrid 主键列的设定

热门文章

  1. SAS学习笔记46 宏变量的可使用范围
  2. springboot 集成fastDfs
  3. 嗯。。 差不多是第一道自己搞出的状态方程 hdu4502 有一点点变形的背包
  4. (三)Lucene之删除更新文档以及luke的基本使用
  5. Java CountingSort
  6. ASP.NET MVC或者.net Core mvc 页面使用富文本控件的 保存问题
  7. office2019激活码 最新各个版本激活码
  8. kong命令(四)upstream
  9. puml 用于代码注释
  10. Lua table直接索引VS缓存索引性能测试小示例