bzoj 3669 lct维护最小生成树
2015-05-13 23:35
218 查看
大概题意:给一个无向图,有a,b两种边权,找一条从1到n的路径,使得max(a[i])+max(b[i])最小a[i],b[i]表示该路径上的边的对应权。
如果用类似最短路的DP来做,显然每个点的状态就必须是一个集合,保存的是一个下凸的点集,表示到达这个点的最小的a,b,这样肯定会挂,但该该种做法已经无法再优化或减少状态了。
考虑枚举其中一个权值b0,然后只考虑所有b权值小于等于b0的边,然后变成简单的问题,因为这个b0不满足二分三分之类的性质,所以肯定不能每次重建图,跑DP,最终的做法是从小到大枚举一维权值,然后不断地加边进入边,维护一个当前图的最小生成树(用LCT实现)。
收获:
1、如果一个东西不满足二分三分,可以尝试从动态的角度,暴力枚举,用数据结构保证复杂度。
View Code
如果用类似最短路的DP来做,显然每个点的状态就必须是一个集合,保存的是一个下凸的点集,表示到达这个点的最小的a,b,这样肯定会挂,但该该种做法已经无法再优化或减少状态了。
考虑枚举其中一个权值b0,然后只考虑所有b权值小于等于b0的边,然后变成简单的问题,因为这个b0不满足二分三分之类的性质,所以肯定不能每次重建图,跑DP,最终的做法是从小到大枚举一维权值,然后不断地加边进入边,维护一个当前图的最小生成树(用LCT实现)。
收获:
1、如果一个东西不满足二分三分,可以尝试从动态的角度,暴力枚举,用数据结构保证复杂度。
/************************************************************** Problem: 3669 User: idy002 Language: C++ Result: Accepted Time:6680 ms Memory:12536 kb ****************************************************************/ #include <cstdio> #include <algorithm> #define oo 0x3f3f3f3f #define N 200010 using namespace std; struct Edge { int u, v, a, b; Edge(){} Edge( int u, int v, int a, int b ):u(u),v(v),a(a),b(b){} bool operator<( const Edge &e ) const { return b<e.b; } }; struct LCT { int son [2], pre , pnt , rtg , ntot; int trash , stot; int val , vmx , vnd , uu , vv ; inline int newnode( int p, int va, int u, int v ) { int nd = stot ? trash[stot--] : ++ntot; pre[nd] = p; son[nd][0] = son[nd][1] = pnt[nd] = 0; rtg[nd] = 0; val[nd] = vmx[nd] = va; vnd[nd] = nd; uu[nd] = u; vv[nd] = v; return nd; } void update( int nd ) { vmx[nd] = val[nd]; vmx[nd] = max( vmx[nd], vmx[son[nd][0]] ); vmx[nd] = max( vmx[nd], vmx[son[nd][1]] ); if( vmx[nd]==val[nd] ) vnd[nd] = nd; else if( vmx[nd]==vmx[son[nd][0]] ) vnd[nd] = vnd[son[nd][0]]; else vnd[nd] = vnd[son[nd][1]]; } void rotate( int nd, int d ) { int p = pre[nd]; int s = son[nd][!d]; int ss = son[s][d]; son[nd][!d] = ss; son[s][d] = nd; if( p ) son[p][ nd==son[p][1] ] = s; else pnt[s]=pnt[nd], pnt[nd]=0; pre[nd] = s; pre[s] = p; if( ss ) pre[ss] = nd; update(nd); update(s); } void bigp( int nd ) { if( pre[nd] ) bigp(pre[nd]); if( rtg[nd] ) { rtg[son[nd][0]] ^= 1; rtg[son[nd][1]] ^= 1; swap( son[nd][0], son[nd][1] ); rtg[nd] = 0; } } void splay( int nd, int top=0 ) { bigp(nd); while( pre[nd]!=top ) { int p=pre[nd]; int nl=nd==son[p][0]; if( pre[p]==top ) { rotate( p, nl ); } else { int pp=pre[p]; int pl=p==son[pp][0]; if( nl==pl ) { rotate( pp, pl ); rotate( p, nl ); } else { rotate( p, nl ); rotate( pp, pl ); } } } } void access( int nd ) { int u = nd; int v = 0; while( u ) { splay( u ); int s=son[u][1]; if( s ) { pre[s] = 0; pnt[s] = u; } son[u][1] = 0; if( v ) { pre[v] = u; pnt[v] = 0; } son[u][1] = v; update(u); v = u; u = pnt[u]; } splay( nd ); } void makeroot( int u ) { access(u); rtg[u] ^= 1; } void init( int n ) { ntot = n; val[0] = -1; } int findroot( int u ) { while( pre[u] ) u=pre[u]; while( pnt[u] ) { u=pnt[u]; while( pre[u] ) u=pre[u]; } return u; } bool sameroot( int u, int v ) { return findroot(u)==findroot(v); } int query( int s, int t ) { makeroot(s); access(t); return vmx[t]; } void addedge( int u, int v, int w ) { // fprintf( stderr, "addedge( %d %d %d )\n", u, v, w ); if( sameroot(u,v) ) { if( query(u,v)<=w ) return; makeroot(u); access(v); int nd = vnd[v]; int l = uu[nd]; int r = vv[nd]; makeroot(l); access(r); bigp(l); int e = son[r][0]; while( son[e][1] ) e=son[e][1]; splay(e); pre[l] = pre[r] = 0; trash[++stot] = e; } makeroot(u); makeroot(v); int nd = newnode(0,w,u,v); pnt[u] = nd; pnt[v] = nd; } void print() { fprintf( stderr, "\n" ); for( int i=1; i<=ntot; i++ ) { int nd = i; for( int j=1; j<=stot; j++ ) if( i==trash[j] ) goto Next; fprintf( stderr, "%d pnt=%d pre=%d ls=%d rs=%d rtg=%d val=%d vmx=%d vnd=%d uu=%d vv=%d\n", nd, pnt[nd], pre[nd], son[nd][0], son[nd][1], rtg[nd], val[nd], vmx[nd], vnd[nd], uu[nd], vv[nd] ); Next:; } } }T; int n, m; Edge edge ; int main() { scanf( "%d%d", &n, &m ); for( int i=1,u,v,a,b; i<=m; i++ ) { scanf( "%d%d%d%d", &u, &v, &a, &b ); edge[i] = Edge(u,v,a,b); } sort( edge+1, edge+1+m ); T.init(n); int ans = oo; for( int i=1,j; i<=m; i=j ) { for( j=i; j<=m; j++ ) { if( edge[j].b==edge[i].b ) T.addedge(edge[j].u,edge[j].v,edge[j].a); else break; } if( !T.sameroot(1,n) ) continue; ans = min( ans, edge[i].b+T.query(1,n) ); } printf( "%d\n", ans==oo ? -1 : ans ); }
View Code
相关文章推荐
- 【BZOJ 3669】 [Noi2014]魔法森林 LCT维护动态最小生成树
- BZOJ2594 [Wc2006]水管局长数据加强版 【LCT维护最小生成树】
- 【LCT维护生成树】BZOJ3669 [Noi2014]魔法森林
- [BZOJ3669]NOI2014魔法森林|LCT|最小生成树
- [BZOJ2594][WC2006]水管局长数据加强版(LCT维护最小生成树)
- BZOJ 2594 LCT维护最小生成树
- ☆ [NOI2014] 魔法森林 「LCT动态维护最小生成树」
- BZOJ 2594: [Wc2006]水管局长数据加强版(LCT+最小生成树+离线)
- bzoj 2594 水管局长 | LCT | 最小生成树
- 【最小生成树】【LCT】【bzoj2594】水管局长数据加强版
- [LCT维护最小生成树 || CDQ分治 || 线段树 并查集 dfs树] Codeforces 603E #334 (Div. 1) E. Pastoral Oddities
- bzoj 2594: [Wc2006]水管局长数据加强版(LCT+最小生成树+离线)
- 3669 [Noi2014]魔法森林(LCT,最小生成树)
- bzoj 1050 [HAOI2006]旅行comf [最小生成树] [动点spfa] [LCT]
- bzoj 2594 [Wc2006]水管局长数据加强版(LCT+最小生成树)
- 【BZOJ3669】[Noi2014]魔法森林【Link-Cut Tree】【最小生成树】
- 【NOI2014T2】魔法森林-LCT维护最小生成树
- 2594: [Wc2006]水管局长数据加强版 LCT维护最小生成树+hash
- BZOJ3669(NOI2014):魔法森林 (LCT维护最小生成树)
- ☆ [WC2006] 水管局长 「LCT动态维护最小生成树」