3669 [Noi2014]魔法森林(LCT,最小生成树)
2016-03-27 19:12
309 查看
【题目链接】
http://www.lydsy.com/JudgeOnline/problem.php?id=3669
【题意】
给定一个无向图,求1-n的路径中最小的max{ai}+max{bi}
【思路】
将边按照a排序。LCT维护关于b的最小生成树。
顺序枚举每条边u,v,如果u,v已经连接则比较u,v路径上的最大边与新边,否则直接相连。
如果1与n连通,则用e.a+max{e.b}更新ans。直观地看,最小生成树上的max{e.b}是1..i条边加入后能够得到的最小b。
_max的初值赋-1,即保证maxe存在,否则无限TLE
【代码】
http://www.lydsy.com/JudgeOnline/problem.php?id=3669
【题意】
给定一个无向图,求1-n的路径中最小的max{ai}+max{bi}
【思路】
将边按照a排序。LCT维护关于b的最小生成树。
顺序枚举每条边u,v,如果u,v已经连接则比较u,v路径上的最大边与新边,否则直接相连。
如果1与n连通,则用e.a+max{e.b}更新ans。直观地看,最小生成树上的max{e.b}是1..i条边加入后能够得到的最小b。
_max的初值赋-1,即保证maxe存在,否则无限TLE
【代码】
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define FOR(a,b,c) for(int a=(b);a<=(c);a++) using namespace std; typedef long long ll; const int N = 1e5+10; ll read() { char c=getchar(); ll f=1,x=0; while(!isdigit(c)) { if(c=='-') f=-1; c=getchar(); } while(isdigit(c)) x=x*10+c-'0',c=getchar(); return x*f; } struct Edge { int u,v,a,b; bool operator < (const Edge& rhs) const { return a<rhs.a; } }e[N<<1]; int en; void adde(int u,int v,int a,int b) { e[++en]=(Edge){u,v,a,b}; } namespace LCT { struct Node { int rev,v,maxe; Node *ch[2],*fa; Node() {} Node(int x) ; void reverse() { rev^=1; swap(ch[0],ch[1]); } void up_push() { if(fa->ch[0]==this||fa->ch[1]==this) fa->up_push(); if(rev) { ch[0]->reverse(); ch[1]->reverse(); rev=0; } } void maintain() { int _max=-1; if(e[ch[0]->maxe].b>_max) _max=e[ch[0]->maxe].b,maxe=ch[0]->maxe; if(e[ch[1]->maxe].b>_max) _max=e[ch[1]->maxe].b,maxe=ch[1]->maxe; if(e[v].b>_max) maxe=v; } } T[N<<1],E[N<<1],*null=&T[0]; Node::Node(int x) { ch[0]=ch[1]=fa=null; rev=0; v=maxe=x; } void rot(Node* o,int d) { Node *p=o->fa; p->ch[d]=o->ch[d^1]; o->ch[d^1]->fa=p; o->ch[d^1]=p; o->fa=p->fa; if(p==p->fa->ch[0]) p->fa->ch[0]=o; else if(p==p->fa->ch[1]) p->fa->ch[1]=o; p->fa=o; p->maintain(); } void splay(Node* o) { o->up_push(); Node* nf,*nff; while(o->fa->ch[0]==o||o->fa->ch[1]==o) { nf=o->fa,nff=nf->fa; if(o==nf->ch[0]) { if(nf==nff->ch[0]) rot(nf,0); rot(o,0); } else { if(nf==nff->ch[1]) rot(nf,1); rot(o,1); } } o->maintain(); } void Access(Node *o) { Node *son=null; while(o!=null) { splay(o); o->ch[1]=son; o->maintain(); son=o; o=o->fa; } } void evert(Node *o) { Access(o); splay(o); o->reverse(); } void Link(Node *u,Node *v) { evert(u); u->fa=v; } void Cut(Node *u,Node *v) { evert(u); Access(v),splay(v); v->ch[0]=u->fa=null; v->maintain(); } Node *find(Node *o) { while(o->fa!=null) o=o->fa; return o; } } using namespace LCT ; int n,m; int query(Node *u,Node* v) { evert(u); Access(v),splay(v); return v->maxe; } int main() { // freopen("in.in","r",stdin); // freopen("out.out","w",stdout); n=read(),m=read(); int u,v,a,b; FOR(i,1,m) { u=read(),v=read(),a=read(),b=read(); adde(u,v,a,b); } FOR(i,1,m) E[i]=Node(i); FOR(i,1,n) T[i]=Node(0); sort(e+1,e+m+1); int ans=1e9; FOR(i,1,m) { int u=e[i].u,v=e[i].v; if(find(&T[u])==find(&T[v])) { int maxe=query(&T[u],&T[v]); if(e[i].b>=e[maxe].b) continue; Cut(&E[maxe],&T[e[maxe].u]); Cut(&E[maxe],&T[e[maxe].v]); } Link(&T[u],&E[i]); Link(&T[v],&E[i]); if(find(&T[1])==find(&T )) { int maxe=query(&T[1],&T ); if(e[maxe].b+e[i].a<ans) ans=e[maxe].b+e[i].a; } } if(ans==1e9) puts("-1"); else printf("%d\n",ans); return 0; }
相关文章推荐
- 《机电传动控制》----学习笔记五
- ZOJ 1654 Place the Robots【二分图匹配】
- 感知哈希算法原理与实现
- 【前端学习】【CSS选择器】
- nyoj 205 大数求余 简单题
- 关于可编辑输入框的focus设置
- 第四周学习进度表
- MAMP软件的安装和使用
- error C2899: typename cannot be used outside a template declaration
- java之yield(),sleep(),wait()区别详解-备忘笔记
- Android 异步加载学习
- 解决im.show()不能显示图片问题
- liunx 网络基础管理
- 全排列
- linxu系统引导&运行级别&chkconfig&/etc/rc/init.d&/etc/rc/rc*.d
- Spark实战-Spark SQL(二)
- 访问者模式
- 敏捷开发方法综述
- 以太网,IP,TCP,UDP数据包分析
- HDU 2795 Billboard (线段树,单点查询)