bzoj 3669 lct维护最小生成树

 

大概题意:给一个无向图,有a,b两种边权,找一条从1到n的路径,使得max(a[i])+max(b[i])最小a[i],b[i]表示该路径上的边的对应权。

如果用类似最短路的DP来做,显然每个点的状态就必须是一个集合,保存的是一个下凸的点集,表示到达这个点的最小的a,b,这样肯定会挂,但该该种做法已经无法再优化或减少状态了。

考虑枚举其中一个权值b0,然后只考虑所有b权值小于等于b0的边,然后变成简单的问题,因为这个b0不满足二分三分之类的性质,所以肯定不能每次重建图,跑DP,最终的做法是从小到大枚举一维权值,然后不断地加边进入边,维护一个当前图的最小生成树(用LCT实现)。

 

收获:

  1、如果一个东西不满足二分三分,可以尝试从动态的角度,暴力枚举,用数据结构保证复杂度。

 

  1 /**************************************************************
  2     Problem: 3669
  3     User: idy002
  4     Language: C++
  5     Result: Accepted
  6     Time:6680 ms
  7     Memory:12536 kb
  8 ****************************************************************/
  9  
 10 #include <cstdio>
 11 #include <algorithm>
 12 #define oo 0x3f3f3f3f
 13 #define N 200010
 14 using namespace std;
 15  
 16 struct Edge {
 17     int u, v, a, b;
 18     Edge(){}
 19     Edge( int u, int v, int a, int b ):u(u),v(v),a(a),b(b){}
 20     bool operator<( const Edge &e ) const { return b<e.b; }
 21 };
 22 struct LCT {
 23     int son[N][2], pre[N], pnt[N], rtg[N], ntot;
 24     int trash[N], stot;
 25     int val[N], vmx[N], vnd[N], uu[N], vv[N];
 26  
 27     inline int newnode( int p, int va, int u, int v ) {
 28         int nd = stot ? trash[stot--] : ++ntot;
 29         pre[nd] = p;
 30         son[nd][0] = son[nd][1] = pnt[nd] = 0;
 31         rtg[nd] = 0;
 32         val[nd] = vmx[nd] = va;
 33         vnd[nd] = nd;
 34         uu[nd] = u;
 35         vv[nd] = v;
 36         return nd;
 37     }
 38     void update( int nd ) {
 39         vmx[nd] = val[nd];
 40         vmx[nd] = max( vmx[nd], vmx[son[nd][0]] );
 41         vmx[nd] = max( vmx[nd], vmx[son[nd][1]] );
 42         if( vmx[nd]==val[nd] )
 43             vnd[nd] = nd;
 44         else if( vmx[nd]==vmx[son[nd][0]] )
 45             vnd[nd] = vnd[son[nd][0]];
 46         else
 47             vnd[nd] = vnd[son[nd][1]];
 48     }
 49     void rotate( int nd, int d ) {
 50         int p = pre[nd];
 51         int s = son[nd][!d];
 52         int ss = son[s][d];
 53  
 54         son[nd][!d] = ss;
 55         son[s][d] = nd;
 56         if( p ) son[p][ nd==son[p][1] ] = s;
 57         else pnt[s]=pnt[nd], pnt[nd]=0;
 58  
 59         pre[nd] = s;
 60         pre[s] = p;
 61         if( ss ) pre[ss] = nd;
 62  
 63         update(nd);
 64         update(s);
 65     }
 66     void bigp( int nd ) {
 67         if( pre[nd] ) bigp(pre[nd]);
 68         if( rtg[nd] ) {
 69             rtg[son[nd][0]] ^= 1;
 70             rtg[son[nd][1]] ^= 1;
 71             swap( son[nd][0], son[nd][1] );
 72             rtg[nd] = 0;
 73         }
 74     }
 75     void splay( int nd, int top=0 ) {
 76         bigp(nd);
 77         while( pre[nd]!=top ) {
 78             int p=pre[nd];
 79             int nl=nd==son[p][0];
 80             if( pre[p]==top ) {
 81                 rotate( p, nl );
 82             } else {
 83                 int pp=pre[p];
 84                 int pl=p==son[pp][0];
 85                 if( nl==pl ) {
 86                     rotate( pp, pl );
 87                     rotate( p, nl );
 88                 } else {
 89                     rotate( p, nl );
 90                     rotate( pp, pl );
 91                 }
 92             }
 93         }
 94     }
 95     void access( int nd ) {
 96         int u = nd;
 97         int v = 0;
 98         while( u ) {
 99             splay( u );
100             int s=son[u][1];
101             if( s ) {
102                 pre[s] = 0;
103                 pnt[s] = u;
104             } 
105             son[u][1] = 0;
106             if( v ) {
107                 pre[v] = u;
108                 pnt[v] = 0;
109             }
110             son[u][1] = v;
111             update(u);
112             v = u;
113             u = pnt[u];
114         }
115         splay( nd );
116     }
117     void makeroot( int u ) {
118         access(u);
119         rtg[u] ^= 1;
120     }
121     void init( int n ) {
122         ntot = n;
123         val[0] = -1;
124     }
125     int findroot( int u ) {
126         while( pre[u] ) u=pre[u];
127         while( pnt[u] ) {
128             u=pnt[u];
129             while( pre[u] ) u=pre[u];
130         }
131         return u;
132     }
133     bool sameroot( int u, int v ) {
134         return findroot(u)==findroot(v);
135     }
136     int query( int s, int t ) {
137         makeroot(s);
138         access(t);
139         return vmx[t];
140     }
141     void addedge( int u, int v, int w ) {
142 //      fprintf( stderr, "addedge( %d %d %d )\n", u, v, w );
143         if( sameroot(u,v) ) {
144             if( query(u,v)<=w ) return;
145             makeroot(u);
146             access(v);
147             int nd = vnd[v];
148             int l = uu[nd];
149             int r = vv[nd];
150             makeroot(l);
151             access(r);
152             bigp(l);
153             int e = son[r][0];
154             while( son[e][1] ) e=son[e][1];
155             splay(e);
156             pre[l] = pre[r] = 0;
157             trash[++stot] = e;
158         } 
159         makeroot(u);
160         makeroot(v);
161         int nd = newnode(0,w,u,v);
162         pnt[u] = nd;
163         pnt[v] = nd;
164     }
165     void print() {
166         fprintf( stderr, "\n" );
167         for( int i=1; i<=ntot; i++ ) {
168             int nd = i;
169             for( int j=1; j<=stot; j++ )
170                 if( i==trash[j] ) 
171                     goto Next;
172             fprintf( stderr, "%d pnt=%d pre=%d ls=%d rs=%d rtg=%d val=%d vmx=%d vnd=%d uu=%d vv=%d\n",
173                     nd, pnt[nd], pre[nd], son[nd][0], son[nd][1], rtg[nd], val[nd], vmx[nd], vnd[nd], uu[nd], vv[nd] );
174 Next:;
175         }
176     }
177 }T;
178  
179 int n, m;
180 Edge edge[N];
181  
182 int main() {
183     scanf( "%d%d", &n, &m );
184     for( int i=1,u,v,a,b; i<=m; i++ ) {
185         scanf( "%d%d%d%d", &u, &v, &a, &b );
186         edge[i] = Edge(u,v,a,b);
187     }
188     sort( edge+1, edge+1+m );
189     T.init(n);
190     int ans = oo;
191     for( int i=1,j; i<=m; i=j ) {
192         for( j=i; j<=m; j++ ) {
193             if( edge[j].b==edge[i].b ) 
194                 T.addedge(edge[j].u,edge[j].v,edge[j].a);
195             else break;
196         }
197         if( !T.sameroot(1,n) ) continue;
198         ans = min( ans, edge[i].b+T.query(1,n) );
199     }
200     printf( "%d\n", ans==oo ? -1 : ans );
201 }
View Code

 

posted @ 2015-05-13 23:35  idy002  阅读(372)  评论(0编辑  收藏  举报