说在前面

刚刚去写了一道SPFA+网络流的糅合题,1A了
闲着没事干开始翻起了status,发现有人在做水管局长,哇这不是LCT嘛!
然后回头看了一下自己写过的寥寥无几的LCT的题,发现都快要忘了
于是决定来补一篇博客,嗯就是这样


题目

BZOJ3669传送门
顺便,BZOJ3668是一道很好玩的题,传送门:BZOJ3668传送门

题目大意

给一个含有N个节点和M条边的无向图,每条边有两个权值ai,bia_i,b_i
现在定义一条从A到B的路径的代价为A到B的路径上的max(ai)+max(bi)max(a_i)+max(b_i)
询问1到N的最小代价。N≤50000,M≤100000N\leq 50000,M\leq 100000

输入输出格式

输入格式:
第1行包含两个整数NN,MM,表示无向图共有NN个节点,MM条边
接下来MM行,每行包含4个正整数u,v,ai,biu, v , a_i , b_i,描述第 ii条无向边。其中uu与vv为该边两个端点的标号,aia_i与bib_i的含义如题所述。 注意数据中可能包含重边与自环

输出格式:
输出一行一个整数,表示答案


解法

这道题很难,me是看了题解的(逃)
正解是LCT,把边权化为点权进行维护

这道题一条边有两个权值,很难用最小生成树或者最短路之类的来跑。那么想到先让一维有序,在另一维上搞事。
最开始所有的点都是不联通的。
先把所有边按照aia_i从小到大排序,然后依次把边加进图里。如果加边之后,图里形成了环,并且环上最大的bib_i比当前边大,就把那条最大的边割掉,否则不加边。
加完边之后,如果11号点和NN号点联通,那么就用当前aia_i和路径上最大的bib_i更新答案

关于正确性。
假设原来1和N不联通,加了一条边变得联通了,那么更新答案,正确性显然。
如果原来1和N就联通,并且新边的bib_i比原来某一条边小。由于aia_i肯定比原来所有边都大,所以只要走这条边,代价就一定会有aia_i,而如果不走这条边,代价一定会有之前某条边的ajaj,而之前某条边肯定已经更新过答案了。
因此,当前的用来更新答案的「aia_i和路径上最大的bib_i」可能不是1到N的代价,并且比1到N的代价大,也正是因此,才不会对当前已有的最优答案产生影响。但是答案一定是某一个「aia_i和路径上最大的bib_i」,因此算法是正确的。


下面是自带大常数的代码

#include <cstdio>
#include <cstring>
#include <algorithm>
#define Eid(x) x+N
using namespace std ;int N , M , ans = 0x3f3f3f3f ;
struct Edge{int u , v , a , b ;bool operator < ( const Edge &A ) const {if( a == A.a ) return b < A.b ;return a < A.a ;}
}E[100005] ;
struct Node{bool reverse ;int val , id ;Node *Bmax , *fa , *ch[2] ;void init( int val_ , int id_ ){reverse = false ;val = val_ , id = id_ ;Bmax = this ;fa = ch[0] = ch[1] = NULL ;}void update(){Bmax = this ;if( ch[0] && Bmax->val < ch[0]->Bmax->val ) Bmax = ch[0]->Bmax ;if( ch[1] && Bmax->val < ch[1]->Bmax->val ) Bmax = ch[1]->Bmax ;}void pushdown(){if( reverse ){swap( ch[0] , ch[1] ) ;reverse = false ;if( ch[0] ) ch[0]->reverse ^= 1 ;if( ch[1] ) ch[1]->reverse ^= 1 ;}}
}w[150005] ;struct Union_set{int f[150005] ;void init(){for( int i = 1 ; i <= N + M ; i ++ )f[i] = i ;}int Find( int x ){if( x == f[x] ) return x ;return f[x] = Find( f[x] ) ;}bool Union( int a , int b ){int F_a = Find( a ) , F_b = Find( b ) ;if( F_a == F_b ) return false ;f[F_a] = F_b ;return true ;}
}U ;bool isRoot( Node *nd ){if( !nd->fa ) return true ;if( nd->fa->ch[0] != nd && nd->fa->ch[1] != nd ) return true ;return false ;
}void Rotate( Node *nd , int aim ){Node *x = nd->ch[aim] ;nd->ch[aim] = x->ch[aim^1] ;if( x->ch[aim^1] ) x->ch[aim^1]->fa = nd ;x->fa = nd->fa ;if( nd->fa ){if( nd->fa->ch[0] == nd ) nd->fa->ch[0] = x ;if( nd->fa->ch[1] == nd ) nd->fa->ch[1] = x ;}nd->fa = x ;x->ch[aim^1] = nd ;nd->update() ;x->update() ;
}Node *sta[100005] ;
void Splay( Node *nd ){int topp = 0 ; Node *tmp = nd ;while( !isRoot( tmp ) ) sta[++topp] = tmp , tmp = tmp->fa ;sta[++topp] = tmp ;for( ; topp ; topp -- ) sta[topp]->pushdown() ;while( !isRoot( nd ) ){Node *fa = nd->fa , *gdfa = fa->fa ;int pn = ( fa->ch[1] == nd ) , pf ;if( gdfa && !isRoot( fa ) ){pf = ( gdfa->ch[1] == fa ) ;if( pn == pf ){Rotate( gdfa , pf ) ;Rotate( fa , pn ) ;} else {Rotate( fa , pn ) ;Rotate( gdfa , pf ) ;}} else Rotate( fa , pn ) ;}
}void Access( Node *nd ){Node *last = NULL ;while( nd ){Splay( nd ) ;nd->ch[1] = last ;nd->update() ;last = nd ;nd = nd->fa ;}
}void Makeroot( Node *nd ){Access( nd ) ;Splay( nd ) ;nd->reverse ^= 1 ;
}void Cut( Node *x , Node *y ){Makeroot( x ) ; Access( y ) ; Splay( y ) ;y->ch[0] = NULL ; x->fa = NULL ;y->update() ;
}void Link( Node *x , Node *y ){Makeroot( x ) ;x->fa = y ;Splay( x ) ;
}Node *Query( Node *x , Node *y ){Makeroot( x ) ; Access( y ) ; Splay( y ) ;return y->Bmax ;
}void dfs( Node *nd , bool ls ){nd->pushdown() ;if( nd->ch[0] ) dfs( nd->ch[0] , 0 ) ;printf( "(%d) %d 's fa is %d\n" ,ls, nd->id , nd->fa?nd->fa->id:-1 ) ;if( nd->ch[1] ) dfs( nd->ch[1] , 1 ) ;
}void solve(){U.init() ;sort( E + 1 , E + M + 1 ) ;for( int i = 1 ; i <= M ; i ++ ){int u = E[i].u , v = E[i].v , a = E[i].a , b = E[i].b ;//  printf( "i : %d  %d to %d A(%d) B(%d)\n" , i , u , v , a , b ) ;w[ Eid(i) ].init( b , i ) ;if( U.Find( u ) == U.Find( v ) ){//  puts( "same set" ) ;Node *Bmax = Query( &w[u] , &w[v] ) ;if( Bmax->val <= b ){//      printf( "%d continue\n" , Bmax->val ) ;continue ;}Cut( &w[ E[Bmax->id].u ] , Bmax ) ;Cut( Bmax , &w[ E[Bmax->id].v ] ) ;} else U.Union( u , v ) ;//  puts( "link" ) ;Link( &w[u] , &w[ Eid(i) ] ) ;Link( &w[ Eid(i) ] , &w[v] ) ;if( U.Find( 1 ) == U.Find( N ) )ans = min( ans , a + Query( &w[1] , &w[N] )->val ) ;//  printf( "over %d\n" , Query( &w[u] , &w[v] )->val ) ;}printf( "%d" , ans == 0x3f3f3f3f ? -1 : ans  ) ;
}int main(){scanf( "%d%d" , &N , &M ) ;for( int i = 1 ; i <= N ; i ++ )w[i].init( 0 , 0-i ) ;for( int i = 1 ; i <= M ; i ++ )scanf( "%d%d%d%d" , &E[i].u , &E[i].v , &E[i].a , &E[i].b ) ;solve() ;
}

[BZOJ3669]-[Noi2014]魔法森林-LCT+并查集相关推荐

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

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

  2. loj2245 [NOI2014]魔法森林 LCT

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

  3. [BZOJ]3669: [Noi2014]魔法森林 lct

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

  4. [BZOJ3669] [NOI2004] 魔法森林 LCT维护最小生成树

    题面 一开始看到这道题虽然知道是跟LCT维护最小生成树相关的但是没有可以的去想. 感觉可以先二分一下总的精灵数,但是感觉不太好做. 又感觉可以只二分一种精灵,用最小生成树算另一种精灵,但是和似乎不单调 ...

  5. [Luogu P2387] [NOI2014]魔法森林 (LCT维护边权)

    题面 传送门:https://www.luogu.org/problemnew/show/P2387 Solution 这题的思想挺好的. 对于这种最大值最小类的问题,很自然的可以想到二分答案.很不幸 ...

  6. NOI2014魔法森林--LCT

    题意:求一条1->n的路径,使得路径上的MAXA+MAXB最小. 做法:以a值从小到大对边排序,动态加边,维护一个最小生成树就行了.如果两个端点不连通,则直接加上,否则就把这个环上b值最大的边删 ...

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

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

  8. [LCT动态树] [NOI2014]魔法森林,[ZJOI2018]历史

    [NOI2014] 魔法森林 题目 按照aaa精灵从小到大排序 按顺序插入每一条边 加入第iii条边后的最小代价为a[i]a[i]a[i]加上从111到nnn的所有路径中最大bbb最小的路径代价 维护 ...

  9. 神spfa [Noi2014]魔法森林

    问题 G: [Noi2014]魔法森林 时间限制: 30 Sec  内存限制: 512 MB 题目描述 为了得到书法大家的真传,小E同学下定决心去拜访住在魔法森林中的隐士.魔法森林可以被看成一个包含个 ...

最新文章

  1. 动画-animation
  2. 开始工业物联网项目需要考虑的八大要点
  3. 电脑怎么分盘win10_电脑时间不对怎么办?Win10电脑时间总是不对的解决方法_电脑故障...
  4. python动力学建模与仿真_PyMC3中的简单动力学模型
  5. 粗看ES6之JSON
  6. 开源需自立!Android、GitHub、Apache 全线告急!
  7. python--图像轮廓findContours
  8. java 双向链表_数据结构-链表、栈和队列
  9. 《人人都该买保险》读书笔记
  10. You need to use a Theme.AppCompat theme
  11. 模糊自适应整定PID控制
  12. WordPress外贸网站速度优化的四个层次
  13. 对车辆路试数据集mtcars进一步分析_【案例】图解电磁阀及其故障诊断分析
  14. Java POI 导出 Excel 单元格 合并单元格 相邻的相同值 合并
  15. 《CSS世界》读书笔记:line-height
  16. ipv6dns服务器无法响应,ipv6获取不到网关和dns服务器
  17. (三)ArcGIS API For Javascript之调用动态地图服务
  18. ActionEnglish Notes
  19. STM32最新是10个案例及操作
  20. 开发App,如何更好的进行技术选型

热门文章

  1. 山寨层出不穷_李开复也搞山寨版
  2. Mac Wi-Fi断断续续的问题
  3. java程序添加背景音乐
  4. 新年伊始勿忘给保险做个“年检”
  5. 感觉好极了----MacBookPro15苹果笔记本外接4K显示器
  6. 各编程语言 + aardio 相互调用示例(简易代码)
  7. 建造者模式( Builder Pattern)
  8. 对话Neo4j首席科学家Jim Webber:图数据库江湖5年后将尘埃落定
  9. 莫名戳中你笑点 法海不懂爱的真相
  10. Fashion MNIST数据集的处理——“...-idx3-ubyte”文件解析