NOI 2014 魔法森林(BZOJ 3669) 题解
对边按a权值排序,按b权值建LCT,按排序后的顺序依次加边。如果加边后形成环则删除环上最大的边。如果起点终点联通则更新答案。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio> 2 #include<algorithm> 3 #define rep(i,n) for(int i=0;i<n;++i) 4 const int MAXN=50000+5; 5 const int MAXM=100000+5; 6 const int INF=~0U>>1; 7 struct Node{ 8 int mxv,v; 9 Node* p,*ch[2],*mx; 10 int e; 11 bool rev; 12 Node() {mxv=v=-1;} 13 inline bool d() const 14 { 15 return p->ch[1]==this; 16 } 17 inline void revIt() 18 { 19 rev^=1; 20 std::swap(ch[0],ch[1]); 21 } 22 inline void setc(Node* t,bool d) 23 { 24 ch[d]=t; 25 t->p=this; 26 } 27 inline void maintain() 28 { 29 mxv=v;mx=this; 30 rep(i,2) if(ch[i]->mxv>mxv) 31 { 32 mxv=ch[i]->mxv; 33 mx=ch[i]->mx; 34 } 35 } 36 inline bool isRoot() const; 37 inline void pushdown(); 38 }Tnull,*null=&Tnull; 39 inline bool Node::isRoot() const 40 { 41 return p==null || (p->ch[0]!=this && p->ch[1]!=this); 42 } 43 inline void Node::pushdown() 44 { 45 if(rev) 46 { 47 rev=0; 48 rep(i,2) if(ch[i]!=null) 49 ch[i]->revIt(); 50 } 51 } 52 inline void rot(Node* t) 53 { 54 Node* p=t->p; 55 p->pushdown();t->pushdown(); 56 bool d=t->d(); 57 if(!p->isRoot()) p->p->setc(t,p->d()); 58 else t->p=p->p; 59 p->setc(t->ch[d^1],d); 60 t->setc(p,d^1); 61 p->maintain(); 62 } 63 inline void splay(Node* t) 64 { 65 t->pushdown(); 66 while(!t->isRoot()) 67 { 68 if(t->p->isRoot()) rot(t); 69 else t->d()==t->p->d()?(rot(t->p),rot(t)):(rot(t),rot(t)); 70 } 71 t->maintain(); 72 } 73 inline void access(Node* u) 74 { 75 for(Node* v=null;u!=null;v=u,u=u->p) 76 { 77 splay(u); 78 u->setc(v,1); 79 u->maintain(); 80 } 81 } 82 inline void makeRoot(Node* u) 83 { 84 access(u); 85 splay(u); 86 u->revIt(); 87 } 88 inline void link(Node* u,Node* v) 89 { 90 makeRoot(u);u->p=v; 91 } 92 inline void cut(Node* u,Node* v) 93 { 94 makeRoot(u); 95 access(v); 96 splay(v); 97 if(v->ch[0]==u) 98 { 99 v->setc(null,0); 100 v->maintain(); 101 u->p=null; 102 } 103 } 104 inline Node* find(Node* u) 105 { 106 for(;u->p!=null;u=u->p); 107 return u; 108 } 109 inline void change(Node* u,int v) 110 { 111 access(u); 112 splay(u); 113 u->v=v; 114 u->maintain(); 115 } 116 inline void getMax(Node* u,Node* v,int& maxv,int& e,Node*& mx) 117 { 118 makeRoot(u); 119 access(v); 120 splay(v); 121 maxv=v->mxv; 122 mx=v->mx; 123 e=v->mx->e; 124 } 125 inline int query(Node* u,Node* v) 126 { 127 makeRoot(u); 128 access(v); 129 splay(v); 130 return v->mxv; 131 } 132 Node mem[MAXN+MAXM],*C=mem; 133 inline Node* newNode(int v,int e) 134 { 135 C->p=C->ch[0]=C->ch[1]=null; 136 C->rev=0; 137 C->v=C->mxv=v; 138 C->mx=C; 139 C->e=e; 140 return C++; 141 } 142 struct Edge{ 143 int u,v,a,b; 144 Edge() {} 145 Edge(int u,int v,int a,int b):u(u),v(v),a(a),b(b) {} 146 bool operator<(const Edge& rhs) const 147 { 148 return a<rhs.a; 149 } 150 }edges[MAXM]; 151 Node* pt[MAXN+MAXM]; 152 int n,m; 153 int ans=INF; 154 int main() 155 { 156 //freopen("1.in","r",stdin); 157 scanf("%d%d",&n,&m); 158 rep(i,m) 159 { 160 int u,v,a,b; 161 scanf("%d%d%d%d",&u,&v,&a,&b); 162 edges[i]=Edge(u,v,a,b); 163 } 164 std::sort(edges,edges+m); 165 rep(i,n) pt[i+1]=newNode(0,-1); 166 rep(i,m) pt[i+n+1]=newNode(edges[i].b,i); 167 rep(i,m) 168 { 169 Edge e=edges[i]; 170 if(find(pt[e.u])!=find(pt[e.v])) link(pt[e.u],pt[i+n+1]),link(pt[e.v],pt[i+n+1]); 171 else 172 { 173 int en,maxv; 174 Node* mx; 175 getMax(pt[e.u],pt[e.v],maxv,en,mx); 176 if(maxv>e.b) 177 { 178 cut(pt[edges[en].u],pt[en+n+1]); 179 cut(pt[edges[en].v],pt[en+n+1]); 180 link(pt[e.u],pt[i+n+1]); 181 link(pt[e.v],pt[i+n+1]); 182 } 183 } 184 if(find(pt[1])==find(pt[n])) ans=std::min(ans,query(pt[1],pt[n])+edges[i].a); 185 } 186 printf("%d\n",ans==INF?-1:ans); 187 return 0; 188 }