记得去年模拟赛的时候好像YY出二分答案枚举a,b的暴力,过了55欸

然后看正解,为了将两维变成一维,将a排序,模拟Kruskal的加边过程,同时维护1到n的最大值,加入一条边e(u,v,a,b)时有以下两种情况:

1) 若u,v已连通,则找出u->v上最大的b',若b<b',则替换之,同时更新答案,注意e一定经过1->n,因为去掉b'所在边时1,n一定不连通,若加上e后1,n连通,则必经过e,由于a是有序的,所以a是路径上最大的a,用a+MAX_b[1->n]更新答案即可。

2)否则,直接加入边e;

显然以上操作可以用lct处理。

对于维护边的信息,考虑把边看成点,与原来的真正的节点一起构成一棵(或多棵)lct,将边的信息存在对应的点上,并保证真正的结点不会对答案产生影响(相当于只起连通的作用),对于这道题,保证w[x]=0(x是结点的结点),x(x是边的结点)即可。

  1. #include<iostream>
  2. #include<cstring>
  3. #include<cstdlib>
  4. #include<algorithm>
  5. #include<cstdio>
  6.  
  7. using namespace std;
  8.  
  9. // The default source begin-----------
  10. const int MXD=~0u>>;
  11. const int D=;
  12. char in[D],out[*],*I=in,*O=out;
  13. #define gc (*I++)
  14. #define pc(x) ((*O++)=x)
  15. #define tQ template <typename Q>
  16. tQ void gt(Q&x) {
  17. static char c,f;
  18. for(f=;c=gc,!isdigit(c);)if(c=='-') f=;
  19. for(x=;isdigit(c);c=gc) x=(x<<) + (x<<) +c-'';
  20. f && (x=-x);
  21. }
  22. tQ void pt(Q x){
  23. static char stk[];
  24. static int top;
  25. top=;
  26. if(x==) pc('');
  27. for(;x;x/=) stk[++top] = x%+'';
  28. for(;top;top--) pc(stk[top]);
  29. }
  30. // The default source end-----------
  31.  
  32. const int Maxn=,Maxm=;
  33. int n,m;
  34. struct Edge{
  35. int u,v,a,b;
  36. inline bool operator < (const Edge&rhs) const {
  37. return a<rhs.a || (a==rhs.a && b<rhs.b);
  38. }
  39. inline void read() {
  40. gt(u),gt(v),gt(a),gt(b);
  41. }
  42. }edges[Maxm];
  43.  
  44. int ch[Maxn+Maxm][],p[Maxn+Maxm],flip[Maxn+Maxm],mx[Maxn+Maxm],w[Maxn+Maxm];
  45.  
  46. #define l ch[x][0]
  47. #define r ch[x][1]
  48. void update(int x){
  49. if(!x) return;
  50. mx[x]=x;
  51. if(w[mx[l]]>w[mx[x]]) mx[x]=mx[l];
  52. if(w[mx[r]]>w[mx[x]]) mx[x]=mx[r];
  53. }
  54. void down(int x) {
  55. if(!x || !flip[x]) return;
  56. swap(l,r);
  57. flip[l]^=;
  58. flip[r]^=;
  59. flip[x]=;
  60. }
  61. #undef l
  62. #undef r
  63. inline bool isroot(int x) {
  64. return ch[p[x]][]!=x && ch[p[x]][]!=x;
  65. }
  66. inline void rotate(int x){
  67. int y=p[x],z=p[y];
  68. int l=ch[y][]==x,r=l^;
  69. if(!isroot(y)){
  70. ch[z][ch[z][]==y]=x;
  71. }
  72. p[y]=x;
  73. p[ch[x][r]]=y;
  74. p[x]=z;
  75.  
  76. ch[y][l]=ch[x][r];
  77. ch[x][r]=y;
  78.  
  79. update(y);
  80. // update(x);
  81. }
  82.  
  83. int stk[Maxn],top;
  84. inline void splay(int x){
  85. stk[top=]=x;
  86. for(int t=x;!isroot(t);stk[++top]=t=p[t]);
  87. for(;top;top--) down(stk[top]);
  88. for(;!isroot(x);){
  89. int y=p[x],z=p[y];
  90. if(!isroot(y)) {
  91. if( (ch[y][]==x) ^ (ch[z][]==y)) rotate(x);
  92. else rotate(y);
  93. }
  94. rotate(x);
  95. }
  96. update(x);
  97. }
  98.  
  99. inline void access(int x) {
  100. for(int t=;x;x=p[t=x]){
  101. splay(x);
  102. ch[x][]=t;
  103. update(x);
  104. }
  105. }
  106.  
  107. inline void newroot(int x) {
  108. access(x);
  109. splay(x);
  110. flip[x]^=;
  111. }
  112.  
  113. inline void n_as(int u,int v){
  114. newroot(u);
  115. access(v);
  116. splay(v);
  117. }
  118.  
  119. inline void Cut(int x,int y) {
  120. n_as(x,y);
  121. ch[y][]=p[x]=;
  122. update(x);
  123. }
  124.  
  125. inline void Link(int x,int y) {
  126. newroot(x);
  127. p[x]=y;
  128. }
  129.  
  130. int fa[Maxn];
  131. int Find(int x) {
  132. return x==fa[x]?x:fa[x]=Find(fa[x]);
  133. }
  134.  
  135. inline bool Union(int x,int y){
  136. x=Find(x);y=Find(y);
  137. if(x==y) return ;
  138. return fa[x]=y,;
  139. }
  140.  
  141. inline void ufs_init(int n) {
  142. for(int i=;i<=n;i++) fa[i]=i;
  143. }
  144.  
  145. inline void init() {
  146. gt(n),gt(m);
  147. for(int i=;i<=m;i++) edges[i].read();
  148. ufs_init(n);
  149. }
  150.  
  151. inline int getroot(int x) {
  152. for(access(x),splay(x);ch[x][];x=ch[x][]);
  153. return x;
  154. }
  155.  
  156. inline void work() {
  157. sort(edges+,edges+m+);
  158. int ans=MXD;
  159. for(int i=;i<=m;i++) {
  160. const Edge& e=edges[i];
  161. w[i+n]=e.b;
  162. if(Union(e.u,e.v)) {
  163. Link(e.u,i+n);
  164. Link(e.v,i+n);
  165. }else {
  166. n_as(e.u,e.v);
  167. int t=mx[e.v];
  168. if(w[t] > e.b) {
  169. Cut(edges[t-n].u,t);
  170. Cut(edges[t-n].v,t);
  171. Link(e.u,i+n);
  172. Link(e.v,i+n);
  173. }
  174. }
  175. newroot();
  176. if(getroot(n)==) {
  177. access(n);
  178. splay(n);
  179. ans = min (ans,e.a + w[mx[n]]);
  180. }
  181. }
  182. printf("%d\n",ans==MXD?-:ans);
  183. }
  184.  
  185. int main() {
  186. #ifdef DEBUG
  187. freopen("forest.in","r",stdin);
  188. freopen("forest.out","w",stdout);
  189. #endif
  190. fread(in,,D,stdin);
  191. init();
  192. work();
  193.  
  194. return ;
  195. }

bzoj3669: [Noi2014]魔法森林 lct的更多相关文章

  1. bzoj3669: [Noi2014]魔法森林 lct版

    先上题目 bzoj3669: [Noi2014]魔法森林 这道题首先每一条边都有一个a,b 我们按a从小到大排序 每次将一条路劲入队 当然这道题权在边上 所以我们将边化为点去连接他的两个端点 当然某两 ...

  2. [bzoj3669][Noi2014]魔法森林——lct

    Brief description 给定一个无向图,求从1到n的一条路径使得这条路径上最大的a和b最小. Algorithm Design 以下内容选自某HN神犇的blog 双瓶颈的最小生成树的感觉, ...

  3. BZOJ 3669: [Noi2014]魔法森林( LCT )

    排序搞掉一维, 然后就用LCT维护加边MST. O(NlogN) ------------------------------------------------------------------- ...

  4. bzoj 3669: [Noi2014]魔法森林 (LCT)

    链接:https://www.lydsy.com/JudgeOnline/problem.php?id=3669 题面: 3669: [Noi2014]魔法森林 Time Limit: 30 Sec  ...

  5. [NOI2014]魔法森林 LCT

    题面 [NOI2014]魔法森林 题解 一条路径的代价为路径上的\(max(a[i]) + max(b[i])\),因为一条边同时有$a[i], b[i]$2种权值,直接处理不好同时兼顾到,所以我们考 ...

  6. loj2245 [NOI2014]魔法森林 LCT

    [NOI2014]魔法森林 链接 loj 思路 a排序,b做动态最小生成树. 把边拆成点就可以了. uoj98.也许lct复杂度写假了..越卡常,越慢 代码 #include <bits/std ...

  7. 【BZOJ3669】[Noi2014]魔法森林 LCT

    终于不是裸的LCT了...然而一开始一眼看上去这是kruskal..不对,题目要求1->n的路径上的每个点的两个最大权值和最小,这样便可以用LCT来维护一个最小生成路(瞎编的...),先以a为关 ...

  8. BZOJ3669[Noi2014]魔法森林——kruskal+LCT

    题目描述 为了得到书法大家的真传,小E同学下定决心去拜访住在魔法森林中的隐士.魔法森林可以被看成一个包含个N节点M条边的无向图,节点标号为1..N,边标号为1..M.初始时小E同学在号节点1,隐士则住 ...

  9. BZOJ3669: [Noi2014]魔法森林(瓶颈生成树 LCT)

    Time Limit: 30 Sec  Memory Limit: 512 MBSubmit: 3558  Solved: 2283[Submit][Status][Discuss] Descript ...

随机推荐

  1. MVC5+EF6 入门完整教程一

    第0课 从0开始 ASP.NET MVC开发模式和传统的WebForm开发模式相比,增加了很多"约定". 直接讲这些 "约定" 会让人困惑,而且东西太多容易忘记 ...

  2. JS键盘码值表

    值得注意的是,keypress事件中获取的keycode.which,都是按键对应的ascii值,而不完全对应下面的列表. 将字符转换为ascii值可以用charCodeAt函数. keycode 8 ...

  3. 【BZOJ1500】【块状链表】维修数列

    Description Input 输入文件的第1行包含两个数N和M,N表示初始时数列中数的个数,M表示要进行的操作数目.第2行包含N个数字,描述初始时的数列.以下M行,每行一条命令,格式参见问题描述 ...

  4. yzoi1109&&viojs1042最小步数的一点看法——回文数

    Description - 问题描述 有一天,雄霸传授本人风神腿法第一式:捕风捉影..............的步法(弟子一:堂主,你大喘气呀.风:你给我闭嘴.)捕风捉影的关键是换气(换不好就会大喘气 ...

  5. javascript 设为首页 | 加入收藏夹 JS代码

    我们介绍一个可兼容所有浏览器的加入收藏代码代码,大概原理是这样的我们根据获取用户navigator.userAgent.toLowerCase()信息来判断浏览器,根据浏览器是否支持加入收藏js命令, ...

  6. Js随机数--网页版的体育彩票选号器

    <script> function Quickpick() { var ball for( ball = 0; ball < 5; ball++) { this[ball] = pa ...

  7. angularjs 实现排序功能

    实现公式:{{orderBy_expression | orderBy:expression:reverse}} Example <script> var app=angular.modu ...

  8. openerp 产品图片的批量写入

    Write a short python script which loops over the image files, encode with base64 and write to OpenER ...

  9. xcode 工具 alcatraz---备用

    简介 Alcatraz 是一个帮你管理 Xcode 插件.模版以及颜色配置的工具.它可以直接集成到 Xcode 的图形界面中,让你感觉就像在使用 Xcode 自带的功能一样. 安装和删除 使用如下的命 ...

  10. SignalTap II应用小实例之触发位置

    概述 SignalTap II一直以来都是笔者调试Altera FPGA设计的利器,最近比较有时间静下心来研究SignalTap II某些细节,虽然笔者有过不少关于SignalTap的使用,且也发表过 ...