思路:
LCA裸题。本来是帮pechpo调错,结果自己写了半天…
设$dis_x$是点$x$到根结点距离,不难想到两点$u$、$v$之间最短距离等于$dis_u+dis_v-dis_{LCA(u,v)}\times 2$。
然后我们可以用Tarjan做,然后发现MLE了。
以为是这题卡vector的内存,于是改成了链式前向星,还是MLE。
后来发现题目的内存限制只有32M,算了算,如果将数据离线保存下来,大约有20000K左右,再加上函数里面的栈,似乎确实有点危险。
最后改成用ST做,只用了5852KB。

  1. #include<cstdio>
  2. #include<cctype>
  3. #include<cstring>
  4. #include<algorithm>
  5. inline int getint() {
  6. char ch;
  7. while(!isdigit(ch=getchar()));
  8. int x=ch^'';
  9. while(isdigit(ch=getchar())) x=(((x<<)+x)<<)+(ch^'');
  10. return x;
  11. }
  12. inline int flog2(const float x) {
  13. return ((unsigned&)x>>&)-;
  14. }
  15. const int V=,logV=;
  16. struct Edge {
  17. int to,w,next;
  18. };
  19. Edge edge[V<<];
  20. int e[V],esz;
  21. inline void add_edge(const int u,const int v,const int w) {
  22. esz++;
  23. edge[esz]=(Edge){v,w,e[u]};
  24. e[u]=esz;
  25. }
  26. bool vis[V];
  27. int dis[V],dep[V];
  28. int anc[V][logV];
  29. inline void init() {
  30. esz=;
  31. memset(vis,,sizeof vis);
  32. memset(dis,,sizeof dis);
  33. memset(anc,,sizeof anc);
  34. memset(dep,,sizeof dep);
  35. memset(e,,sizeof e);
  36. }
  37. void dfs(const int x,const int par) {
  38. vis[x]=true;
  39. anc[x][]=par;
  40. dep[x]=dep[par]+;
  41. for(int i=e[x];i;i=edge[i].next) {
  42. int &y=edge[i].to;
  43. if(y==par) continue;
  44. dis[y]=dis[x]+edge[i].w;
  45. dfs(y,x);
  46. }
  47. }
  48. int LCA(int a,int b) {
  49. if(dep[a]<dep[b]) std::swap(a,b);
  50. for(int i=flog2(dep[a]);i>=;i--) {
  51. if(dep[a]-(<<i)>=dep[b]) a=anc[a][i];
  52. }
  53. if(a==b) return a;
  54. for(int i=flog2(dep[a]);i>=;i--) {
  55. if(anc[a][i]!=anc[b][i]) a=anc[a][i],b=anc[b][i];
  56. }
  57. return anc[a][];
  58. }
  59. int main() {
  60. int n,m,q;
  61. while(~scanf("%d%d%d",&n,&m,&q)) {
  62. init();
  63. while(m--) {
  64. int u=getint(),v=getint(),w=getint();
  65. add_edge(u,v,w);
  66. add_edge(v,u,w);
  67. }
  68. for(int i=;i<=n;i++) {
  69. if(!vis[i]) dfs(i,);
  70. }
  71. for(int j=;j<=flog2(n);j++) {
  72. for(int i=;i<=n;i++) {
  73. anc[i][j]=anc[anc[i][j-]][j-];
  74. }
  75. }
  76. while(q--) {
  77. int u=getint(),v=getint();
  78. if(int lca=LCA(u,v)) {
  79. printf("%d\n",dis[u]+dis[v]-dis[lca]*);
  80. }
  81. else {
  82. puts("Not connected");
  83. }
  84. }
  85. }
  86. return ;
  87. }

本来用Tarjan算法是MLE的,当时是用了三个数组$qx[Q]$,$qy[Q]$,$lca[Q]$,分别存储每一个$x$,$y$和$LCA(x,y)$,Tarjan的时候求出LCA。最后答案输出的时候计算距离。
后来考虑在Tarjan的同时直接将它们之间的距离求出来,这样一下子就节省了两个数组,最后跑了29376K,还是勉强卡过去。

  1. #include<cstdio>
  2. #include<cctype>
  3. #include<cstring>
  4. inline int getint() {
  5. char ch;
  6. while(!isdigit(ch=getchar()));
  7. int x=ch^'';
  8. while(isdigit(ch=getchar())) x=(((x<<)+x)<<)+(ch^'');
  9. return x;
  10. }
  11. const int V=,E=,Q=;
  12. struct Edge {
  13. int to,w,next;
  14. };
  15. Edge edge[E<<];
  16. int e[V],esz;
  17. inline void add_edge(int u,int v,int w) {
  18. esz++;
  19. edge[esz]=(Edge){v,w,e[u]};
  20. e[u]=esz;
  21. }
  22. struct Query {
  23. int to,id,next;
  24. };
  25. Query query[Q<<];
  26. int q[V],qsz;
  27. inline void add_query(int u,int v,int id) {
  28. qsz++;
  29. query[qsz]=(Query){v,id,q[u]};
  30. q[u]=qsz;
  31. }
  32. class DisjointSet {
  33. private:
  34. int anc[V];
  35. public:
  36. void reset() {
  37. for(int i=;i<V;i++) anc[i]=i;
  38. }
  39. int Find(int x) {
  40. return x==anc[x]?x:anc[x]=Find(anc[x]);
  41. }
  42. void Union(int x,int y) {
  43. anc[Find(x)]=Find(y);
  44. }
  45. bool isConnected(int x,int y) {
  46. return Find(x)==Find(y);
  47. }
  48. };
  49. DisjointSet s;
  50. int ans[Q];
  51. int vis[V];
  52. int dis[V]={};
  53. int root;
  54. void Tarjan(int x,int par) {
  55. vis[x]=root;
  56. for(int i=e[x];i;i=edge[i].next) {
  57. int y=edge[i].to;
  58. if(y!=par) {
  59. dis[y]=dis[x]+edge[i].w;
  60. Tarjan(y,x);
  61. s.Union(y,x);
  62. }
  63. }
  64. for(int i=q[x];i;i=query[i].next) {
  65. int y=query[i].to;
  66. if(vis[y]==root) {
  67. ans[query[i].id]=dis[x]+dis[y]-dis[s.Find(y)]*;
  68. }
  69. }
  70. }
  71. inline void init() {
  72. s.reset();
  73. esz=qsz=;
  74. for(int i=;i<Q;i++) ans[i]=-;
  75. memset(vis,,sizeof vis);
  76. memset(e,,sizeof e);
  77. memset(q,,sizeof q);
  78. }
  79. int main() {
  80. int n,m,q;
  81. while(~scanf("%d%d%d",&n,&m,&q)) {
  82. init();
  83. while(m--) {
  84. int u=getint(),v=getint(),w=getint();
  85. add_edge(u,v,w);
  86. add_edge(v,u,w);
  87. }
  88. for(int i=;i<q;i++) {
  89. int u=getint(),v=getint();
  90. add_query(u,v,i);
  91. add_query(v,u,i);
  92. }
  93. for(int i=;i<=n;i++) {
  94. if(!vis[i]) {
  95. root=i;
  96. Tarjan(i,);
  97. }
  98. }
  99. for(int i=;i<q;i++) {
  100. if(~ans[i]) {
  101. printf("%d\n",ans[i]);
  102. }
  103. else {
  104. puts("Not connected");
  105. }
  106. }
  107. }
  108. return ;
  109. }

[HDU2874]Connections between cities的更多相关文章

  1. hdu-2874 Connections between cities(lca+tarjan+并查集)

    题目链接: Connections between cities Time Limit: 10000/5000 MS (Java/Others)     Memory Limit: 32768/327 ...

  2. [hdu2874]Connections between cities(LCA+并查集)

    题意:n棵树,求任意两点的最短距离. 解题关键:并查集判断两点是否位于一棵树上,然后求最短距离即可.此题可以直接对全部区间直接进行st表,因为first数组会将连接的两点的区间表示出来. //#pra ...

  3. HDU2874 Connections between cities 最近公共祖先

    第一次按常规的方法求,将所有的查询的u,v,和最近公共祖先都保存起来,然后用tarjan+并查集求最近公共祖先.因为询问的次数过多,所以在保存查询的时候总是MLE,后来参考了一下别人的代码,才突然觉悟 ...

  4. hdu 2874 Connections between cities [LCA] (lca->rmq)

    Connections between cities Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (J ...

  5. Connections between cities

    Connections between cities Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java ...

  6. HDU 2874 Connections between cities(LCA Tarjan)

    Connections between cities [题目链接]Connections between cities [题目类型]LCA Tarjan &题意: 输入一个森林,总节点不超过N ...

  7. hdu 2874 Connections between cities 带权lca判是否联通

    Connections between cities Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (J ...

  8. hdu 2874 Connections between cities(st&rmq LCA)

    Connections between cities Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (J ...

  9. hdu 2874 Connections between cities (并查集+LCA)

    Connections between cities Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (J ...

随机推荐

  1. 基于序列化技术(Protobuf)的socket文件传输

    好像好久都没更博文了,没办法,最近各种倒霉事情,搞到最近真的没什么心情,希望之后能够转运吧. 言归正传,这次我要做的是基于序列化技术的socket文件传输来无聊练一下手. 一.socket文件传输 之 ...

  2. JavaScript编写风格指南 (二)

    七:注释 // 频繁的使用注释有助于他人理解你的代码// 1.代码晦涩难懂// 2.可能被误认为是错误的代码// 3.必要但不明显的针对特定浏览器的代码// 4.对于对象,方法或者属性,生成文档是有必 ...

  3. TED_Topic8:How to control someone else's arm with your brain

    By Greg Gage (Neuroscientist) Greg Gage is on a mission to make brain science accessible to all. In ...

  4. Android的layout_weight和weightSum

    先看一下weightSum属性的功能描述:定义weight总和的最大值.如果未指定该值,以所有子视图的layout_weight属性的累加值作为总和的最大值.把weightSum的定义搁在这里,先去看 ...

  5. 【C++】cmdline——轻量级的C++命令行解析库

    1.说明 cmdline是一个轻量级的c++命令行参数解析工具,全部源码只有一个cmdline.h头文件. 2.代码 20171210_命令行进行解析.cpp // 20171210_命令行进行解析. ...

  6. VAE(Variational Autoencoder)的原理

    Kingma, Diederik P., and Max Welling. "Auto-encoding variational bayes." arXiv preprint ar ...

  7. mysql学习------二进制日志

    一.什么是二进制日志 1.记录对数据发生或潜在发生更改的sql语句 2.二进制格式保存 3.用途广泛,包括 a.查看数据库变更历史 b.数据库增量备份 c.数据库灾难恢复 d.mysql replic ...

  8. RTS与CTS的含义【转】

    转自:http://www.cnblogs.com/sunyubo/archive/2010/04/21/2282176.html 一.RS232标准中的RTS与CTS RTS,CTS------请求 ...

  9. 在线建立或重做mysql主从复制架构方法(传统模式和GTID模式)【转】

    mysql主从复制架构,是mysql数据库主要特色之一,绝大多数公司都有用到. 而GTID模式是基于事务的复制模式的意思,发展到现在也是越来越多人用. 以前很多文章,介绍搭建mysql主从复制架构,是 ...

  10. LeetCode(19):删除链表的倒数第N个节点

    Medium! 题目描述: 给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点. 示例: 给定一个链表: 1->2->3->4->5, 和 n = 2. 当删除了 ...