Vijos1865 NOI2014 魔法森林 LCT维护生成树
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Vijos1865 NOI2014 魔法森林 LCT维护生成树相关的知识,希望对你有一定的参考价值。
基本思路:
首先按照weightA升序排序,然后依次在图中加边,并维护起点到终点路径上weightB的最大值
如果加边过程中生成了环,则删除环中weightB最大的边
由于是无向图,点之间没有拓扑序,所以在建立LCT模型时,可以将原图的边也视为点,这样就转化成了维护路径上的点权最大值(Orz Hzwer)
点的连通性可以用并查集维护
AC code:(其实Splay双旋一次时只需要进行3次update,而代码中舍弃了这个优化)
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 5 const int maxN=50005; 6 const int maxM=100005; 7 const int inf=0x3f3f3f3f; 8 9 struct Edge 10 { 11 int u,v; 12 int weightA,weightB; 13 14 void assign(int _u,int _v,int _wa,int _wb) 15 { 16 u=_u; v=_v; weightA=_wa; weightB=_wb; 17 } 18 bool operator < (const Edge& other) const 19 { 20 return this->weightA < other.weightA; 21 } 22 }; 23 24 Edge elist[maxM]; 25 26 inline int getMaxIdx(int u,int v) 27 { 28 return elist[u].weightB > elist[v].weightB ? u : v; 29 } //Let elist[0].weightB = -inf 30 31 struct Splay 32 { 33 int idx; 34 int maxIdx; 35 bool rev; 36 Splay* child[2]; 37 Splay* parent; 38 39 void init(int id) 40 { 41 idx=maxIdx=id; 42 rev=false; 43 child[0]=child[1]=parent=0; 44 } 45 bool isRoot() 46 { 47 if(!parent) return true; 48 else return this!=parent->child[0] && this!=parent->child[1]; 49 } 50 void update() 51 { 52 maxIdx=idx; 53 if(child[0]) maxIdx=getMaxIdx(this->maxIdx,child[0]->maxIdx); 54 if(child[1]) maxIdx=getMaxIdx(this->maxIdx,child[1]->maxIdx); 55 } 56 void reverse() 57 { 58 if(!isRoot()) parent->reverse(); 59 if(rev) { 60 std::swap(child[0],child[1]); 61 if(child[0]) child[0]->rev ^= 1; 62 if(child[1]) child[1]->rev ^= 1; 63 this->rev=0; 64 } 65 } 66 void setRev() { rev^=1; } 67 void rotate(int dir) 68 { 69 Splay* temp=parent; 70 this->parent=temp->parent; 71 if(parent) 72 { 73 if(temp==parent->child[0]) parent->child[0]=this; 74 else if(temp==parent->child[1]) parent->child[1]=this; 75 } 76 temp->child[dir^1]=this->child[dir]; 77 if(child[dir]) child[dir]->parent=temp; 78 child[dir]=temp; 79 temp->parent=this; 80 temp->update(); 81 this->update(); 82 } 83 void splay() 84 { 85 reverse(); 86 while(!isRoot()) 87 { 88 int st(0); 89 if(this==parent->child[0]) st|=1; 90 else st|=2; 91 if(!parent->isRoot()) 92 { 93 if(parent==parent->parent->child[0]) st|=4; 94 else st|=8; 95 } 96 switch(st) 97 { 98 case 1: rotate(1); break; 99 case 2: rotate(0); break; 100 case 5: parent->rotate(1); this->rotate(1); break; 101 case 6: rotate(0); rotate(1); break; 102 case 9: rotate(1); rotate(0); break; 103 case 10:parent->rotate(0); this->rotate(0); break; 104 } 105 } 106 } 107 }; 108 109 Splay node[maxN+maxM]; 110 111 int access(int idx) 112 { 113 Splay *cur,*last; 114 for(cur=node+idx,last=0;cur;last=cur,cur=cur->parent) 115 { 116 cur->splay(); 117 cur->child[1]=last; 118 cur->update(); 119 } 120 return last->maxIdx; 121 } 122 inline void setAsRoot(int idx) 123 { 124 access(idx); 125 node[idx].splay(); 126 node[idx].setRev(); 127 } 128 inline void link(int u,int v) 129 { 130 setAsRoot(u); 131 node[u].parent=node+v; 132 } 133 inline void cut(int u,int v) 134 { 135 setAsRoot(u); 136 access(v); 137 node[v].splay(); 138 node[v].child[0]=node[u].parent=0; 139 node[v].update(); 140 } 141 inline int query(int u,int v) 142 { 143 setAsRoot(u); 144 return access(v); 145 } 146 147 int N,M; 148 int center[maxN]; 149 150 int getCenter(int idx) 151 { 152 return center[idx]==idx ? idx : 153 center[idx]=getCenter(center[idx]); 154 } 155 void input() 156 { 157 scanf("%d%d",&N,&M); 158 int u,v,wa,wb; 159 for(int i=1;i<=M;i++) 160 { 161 scanf("%d%d%d%d",&u,&v,&wa,&wb); 162 if(u==v) { --i; --M; } 163 else elist[i].assign(u,v,wa,wb); 164 } 165 } 166 void init() 167 { 168 elist[0].weightB=-inf; 169 std::sort(elist+1,elist+M+1); 170 for(int i=1;i<=M;i++) node[i].init(i); 171 for(int i=1;i<=N;i++) node[i+M].init(0); 172 for(int i=1;i<=N;i++) center[i]=i; 173 } 174 void addEdge(int e) 175 { 176 int& u=elist[e].u; 177 int& v=elist[e].v; 178 int cu=getCenter(u); 179 int cv=getCenter(v); 180 if(cu!=cv) 181 { 182 link(e,M+u); 183 link(e,M+v); 184 center[cu]=cv; 185 } 186 else { 187 int mx=query(M+u,M+v); 188 if(elist[e].weightB < elist[mx].weightB) 189 { 190 cut(mx,M+elist[mx].u); 191 cut(mx,M+elist[mx].v); 192 link(e,M+u); 193 link(e,M+v); 194 } 195 } 196 } 197 int solve() 198 { 199 int ans(inf); 200 init(); 201 for(int i=1;i<=M;i++) 202 { 203 addEdge(i); 204 if(getCenter(1)==getCenter(N)) 205 { 206 int mx=query(M+1,M+N); 207 ans=std::min(ans,elist[i].weightA+elist[mx].weightB); 208 } 209 } 210 return (ans==inf)?-1:ans; 211 } 212 213 int main() 214 { 215 input(); 216 printf("%d\\n",solve()); 217 return 0; 218 }
——————分割线——————
这道题我Debug了2天共计5h,最后偶然间查明了死因居然是——
1 #ifdef WRONG_SPLAY_CODE 2 void Splay::splay() 3 { 4 reverse(); 5 while(!isRoot()) 6 { 7 int st(0); 8 if(this==parent->child[0]) st|=1; 9 else st|=2; 10 if(!parent->isRoot()) 11 { 12 if(parent==parent->parent->child[0]) st|=4; 13 else st|=8; 14 } 15 switch(st) 16 { 17 case 1: rotate(1); break; 18 case 2: rotate(0); break; 19 case 5: parent->rotate(1); this->rotate(1); break; 20 case 6: rotate(1); rotate(0); break; 21 case 9: rotate(0); rotate(1); break; 22 case 10:parent->rotate(0); this->rotate(0); break; 23 } 24 } 25 } 26 #endif
不过在Debug期间,参考了不少其他神犇的AC代码,也学到了各种姿势,算是因祸得福吧……
以上是关于Vijos1865 NOI2014 魔法森林 LCT维护生成树的主要内容,如果未能解决你的问题,请参考以下文章