3669 [Noi2014]魔法森林(LCT,最小生成树)
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了3669 [Noi2014]魔法森林(LCT,最小生成树)相关的知识,希望对你有一定的参考价值。
【题目链接】
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
【代码】
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #define FOR(a,b,c) for(int a=(b);a<=(c);a++) 6 using namespace std; 7 8 typedef long long ll; 9 const int N = 1e5+10; 10 11 ll read() { 12 char c=getchar(); 13 ll f=1,x=0; 14 while(!isdigit(c)) { 15 if(c==‘-‘) f=-1; c=getchar(); 16 } 17 while(isdigit(c)) 18 x=x*10+c-‘0‘,c=getchar(); 19 return x*f; 20 } 21 22 struct Edge { 23 int u,v,a,b; 24 bool operator < (const Edge& rhs) const { 25 return a<rhs.a; 26 } 27 }e[N<<1]; 28 int en; 29 void adde(int u,int v,int a,int b) 30 { 31 e[++en]=(Edge){u,v,a,b}; 32 } 33 34 namespace LCT { 35 36 struct Node { 37 int rev,v,maxe; 38 Node *ch[2],*fa; 39 Node() {} 40 Node(int x) ; 41 void reverse() { 42 rev^=1; 43 swap(ch[0],ch[1]); 44 } 45 void up_push() { 46 if(fa->ch[0]==this||fa->ch[1]==this) 47 fa->up_push(); 48 if(rev) { 49 ch[0]->reverse(); 50 ch[1]->reverse(); 51 rev=0; 52 } 53 } 54 void maintain() { 55 int _max=-1; 56 if(e[ch[0]->maxe].b>_max) 57 _max=e[ch[0]->maxe].b,maxe=ch[0]->maxe; 58 if(e[ch[1]->maxe].b>_max) 59 _max=e[ch[1]->maxe].b,maxe=ch[1]->maxe; 60 if(e[v].b>_max) maxe=v; 61 } 62 } T[N<<1],E[N<<1],*null=&T[0]; 63 Node::Node(int x) { 64 ch[0]=ch[1]=fa=null; 65 rev=0; v=maxe=x; 66 } 67 68 void rot(Node* o,int d) { 69 Node *p=o->fa; 70 p->ch[d]=o->ch[d^1]; 71 o->ch[d^1]->fa=p; 72 o->ch[d^1]=p; 73 o->fa=p->fa; 74 if(p==p->fa->ch[0]) 75 p->fa->ch[0]=o; 76 else if(p==p->fa->ch[1]) 77 p->fa->ch[1]=o; 78 p->fa=o; 79 p->maintain(); 80 } 81 void splay(Node* o) { 82 o->up_push(); 83 Node* nf,*nff; 84 while(o->fa->ch[0]==o||o->fa->ch[1]==o) { 85 nf=o->fa,nff=nf->fa; 86 if(o==nf->ch[0]) { 87 if(nf==nff->ch[0]) rot(nf,0); 88 rot(o,0); 89 } else { 90 if(nf==nff->ch[1]) rot(nf,1); 91 rot(o,1); 92 } 93 } 94 o->maintain(); 95 } 96 void Access(Node *o) { 97 Node *son=null; 98 while(o!=null) { 99 splay(o); 100 o->ch[1]=son; 101 o->maintain(); 102 son=o; o=o->fa; 103 } 104 } 105 void evert(Node *o) { 106 Access(o); 107 splay(o); 108 o->reverse(); 109 } 110 void Link(Node *u,Node *v) { 111 evert(u); 112 u->fa=v; 113 } 114 void Cut(Node *u,Node *v) { 115 evert(u); 116 Access(v),splay(v); 117 v->ch[0]=u->fa=null; 118 v->maintain(); 119 } 120 Node *find(Node *o) { 121 while(o->fa!=null) o=o->fa; 122 return o; 123 } 124 125 } 126 using namespace LCT ; 127 128 int n,m; 129 130 int query(Node *u,Node* v) 131 { 132 evert(u); 133 Access(v),splay(v); 134 return v->maxe; 135 } 136 137 int main() 138 { 139 // freopen("in.in","r",stdin); 140 // freopen("out.out","w",stdout); 141 n=read(),m=read(); 142 int u,v,a,b; 143 FOR(i,1,m) { 144 u=read(),v=read(),a=read(),b=read(); 145 adde(u,v,a,b); 146 } 147 FOR(i,1,m) E[i]=Node(i); 148 FOR(i,1,n) T[i]=Node(0); 149 sort(e+1,e+m+1); 150 int ans=1e9; 151 FOR(i,1,m) { 152 int u=e[i].u,v=e[i].v; 153 if(find(&T[u])==find(&T[v])) { 154 int maxe=query(&T[u],&T[v]); 155 if(e[i].b>=e[maxe].b) continue; 156 Cut(&E[maxe],&T[e[maxe].u]); 157 Cut(&E[maxe],&T[e[maxe].v]); 158 } 159 Link(&T[u],&E[i]); 160 Link(&T[v],&E[i]); 161 if(find(&T[1])==find(&T[n])) { 162 int maxe=query(&T[1],&T[n]); 163 if(e[maxe].b+e[i].a<ans) ans=e[maxe].b+e[i].a; 164 } 165 } 166 if(ans==1e9) puts("-1"); 167 else printf("%d\n",ans); 168 return 0; 169 }
以上是关于3669 [Noi2014]魔法森林(LCT,最小生成树)的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ 3669: [Noi2014]魔法森林( LCT )