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 )

沉迷Link-Cut tree无法自拔之:[BZOJ3669][Noi2014] 魔法森林

BZOJ3669[Noi2014]魔法森林 LCT

bzoj3669 [Noi2014]魔法森林——LCT

BZOJ 3669NOI 2014魔法森林 LCT+枚举边

bzoj3669: [Noi2014]魔法森林 lct