zoukankan      html  css  js  c++  java
  • Solution -「UOJ #87」mx 的仙人掌

    (mathcal{Description})

      Link.

      给出含 (n) 个结点 (m) 条边的仙人掌图。(q) 次询问,每次询问给出一个点集 (S),求 (S) 内两两结点最短距离的最大值。

      (n,sum|S|le3 imes10^5)

    (mathcal{Solution})

      圆方树 + 虚树 = 虚圆方树!

      首先,考虑对于整个仙人掌怎么求答案:建出圆方树,DP 记录子树最深结点深度,在方点处单调队列合并圆儿子的两条链贡献答案即可。

      接下来,只需要把“虚圆方树”给弄出来就好。关键即在于满足方点周围一定裹着它自己管辖的圆点的性质,那么在建虚树边时特殊考虑一下就完成啦。

    (mathcal{Code})

    /* Clearink */
    
    #include <cstdio>
    #include <vector>
    
    #define rep( i, l, r ) for ( int i = l, repEnd##i = r; i <= repEnd##i; ++i )
    #define per( i, r, l ) for ( int i = r, repEnd##i = l; i >= repEnd##i; --i )
    
    inline char fgc() {
    	static char buf[1 << 17], *p = buf, *q = buf;
    	return p == q && ( q = buf + fread( p = buf, 1, 1 << 17, stdin ), p == q )
    		? EOF : *p++;
    }
    
    inline int rint() {
    	int x = 0; char s = fgc();
    	for ( ; s < '0' || '9' < s; s = fgc() );
    	for ( ; '0' <= s && s <= '9'; s = fgc() ) x = x * 10 + ( s ^ '0' );
    	return x;
    }
    
    template<typename Tp>
    inline void wint( Tp x ) {
    	if ( x < 0 ) putchar( '-' ), x = -x;
    	if ( 9 < x ) wint( x / 10 );
    	putchar( x % 10 ^ '0' );
    }
    
    typedef long long LL;
    
    template<typename Tp>
    inline void chkmin( Tp& a, const Tp b ) { b < a && ( a = b ); }
    template<typename Tp>
    inline void chkmax( Tp& a, const Tp b ) { a < b && ( a = b ); }
    inline LL lmin( const LL a, const LL b ) { return a < b ? a : b; }
    
    const int MAXN = 3e5, MAXM = MAXN << 1, MAXLG = 20;
    const LL LINF = 1ll << 60;
    int n, m;
    
    template<const int NODE, const int EDGE>
    struct Graph {
    	int ecnt, head[NODE], to[EDGE], nxt[EDGE];
    	LL len[EDGE];
    	Graph(): ecnt( 1 ) {}
    
    	inline void operator () ( const int s, const int t, const LL w ) {
    		#ifdef RYBY
    			printf( "%d %d %lld
    ", s, t, w );
    		#endif
    		to[++ecnt] = t, len[ecnt] = w, nxt[ecnt] = head[s], head[s] = ecnt;
    	}
    };
    #define adj( t, u, v ) 
    	for ( int e = t.head[u], v; v = t.to[e], e; e = t.nxt[e] )
    
    Graph<MAXN + 5, MAXM * 2 + 5> src;
    
    int vnode, dfc, dfn[MAXN * 2 + 5], low[MAXN + 5];
    LL pre[MAXN * 2 + 5];
    Graph<MAXN * 2 + 5, MAXN * 2 + 5> cac;
    
    inline void buildCactus( const int u, const int f ) {
    	static int top = 0, stk[MAXN + 5];
    	dfn[u] = low[u] = ++dfc, stk[++top] = u;
    	adj( src, u, v ) if ( v != f ) {
    		if ( !dfn[v] ) {
    			 buildCactus( v, u );
    			 chkmin( low[u], low[v] );
    
    			 if ( low[v] >= dfn[u] ) {
    				cac( u, ++vnode, 0 ), pre[vnode] = src.len[e];
    				int las = u, ttop = top, cnt = 0;
    				do {
    					int w = stk[top];
    					for ( int i = src.head[w]; i; i = src.nxt[i] ) {
    						if ( i ^ e ^ 1 && src.to[i] == las ) {
    							++cnt;
    							pre[w] = pre[las] + src.len[i];
    							pre[vnode] += src.len[i];
    							break;
    						}
    					}
    					las = w;
    				} while ( stk[top--] != v );
    
    				do {
    					int w = stk[ttop];
    					cac( vnode, w, cnt ?
    						lmin( pre[w], pre[vnode] - pre[w] ) : pre[vnode] );
    				} while ( stk[ttop--] != v );
    			 }
    		} else chkmin( low[u], dfn[v] );
    	}
    }
    
    // `dfc` and `dfn` was used by `buildCactus`, pay attention.
    int dep[MAXN * 2 + 5], fa[MAXN * 2 + 5][MAXLG + 5];
    LL dis[MAXN * 2 + 5];
    
    inline void initCactus( const int u ) {
    	dfn[u] = ++dfc;
    	for ( int i = 1; fa[u][i - 1]; fa[u][i] = fa[fa[u][i - 1]][i - 1], ++i );
    	adj( cac, u, v ) {
    		dep[v] = dep[u] + 1, dis[v] = dis[u] + cac.len[e], fa[v][0] = u;
    		initCactus( v );
    	}
    }
    
    inline int lca( int u, int v ) {
    	if ( dep[u] < dep[v] ) u ^= v ^= u ^= v;
    	per ( i, MAXLG, 0 ) if ( dep[fa[u][i]] >= dep[v] ) u = fa[u][i];
    	if ( u == v ) return u;
    	per ( i, MAXLG, 0 ) if ( fa[u][i] != fa[v][i] ) u = fa[u][i], v = fa[v][i];
    	return fa[u][0];
    }
    
    inline int climb( int u, const int par ) {
    	per ( i, MAXLG, 0 ) if ( dep[fa[u][i]] > dep[par] ) u = fa[u][i];
    	return u;
    }
    
    Graph<MAXN * 2 + 5, MAXN * 2 + 5> virc;
    
    inline void vlink( int s, int t ) {
    	// s is t's ancestor in cactus tree.
    	if ( s > n ) {
    		int is = climb( t, s );
    		virc( s, is, dis[is] - dis[s] ), s = is;
    	}
    	if ( t > n ) {
    		virc( fa[t][0], t, dis[t] - dis[fa[t][0]] ), t = fa[t][0];
    	}
    	if ( s != t ) virc( s, t, dis[t] - dis[s] );
    }
    
    inline void buildVirCac( std::vector<int>& vec ) {
    	static int top, stk[MAXN * 2 + 5];
    	virc.ecnt = 0, stk[top = 1] = 1;
    	
    	std::sort( vec.begin(), vec.end(), []( const int a, const int b ) {
    		return dfn[a] < dfn[b];
    	} );
    
    	for ( int u: vec ) if ( u != 1 ) {
    		int anc = lca( stk[top], u );
    		while ( dep[stk[top]] > dep[anc] ) {
    			int a = stk[top--], b = dep[stk[top]] < dep[anc] ? anc : stk[top];
    			vlink( b, a );
    		}
    		if ( stk[top] != anc ) stk[++top] = anc;
    		stk[++top] = u;
    	}
    
    	while ( top > 1 ) {
    		int a = stk[top--], b = stk[top];
    		vlink( b, a );
    	}
    }
    
    LL ans, f[MAXN * 2 + 5];
    bool book[MAXN + 5];
    
    inline void contri( const int u, const std::vector<int>& cir ) {
    	static int que[MAXN + 5], hd, tl;
    	int sz = int( cir.size() ); LL half = pre[u] >> 1;
    	
    #define val( i ) ( pre[cir[i]] + ( i >= sz >> 1 ? pre[u] : 0 ) )
    
    	que[hd = tl = 1] = 0;
    	rep ( i, 1, sz - 1 ) {
    		while ( hd <= tl && val( i ) - val( que[hd] ) > half ) ++hd;
    
    		if ( hd <= tl ) {
    			chkmax( ans, f[cir[que[hd]]] - val( que[hd] )
    				+ f[cir[i]] + val( i ) );
    		}
    
    		while ( hd <= tl && f[cir[que[tl]]] - val( que[tl] )
    			<= f[cir[i]] - val( i ) ) --tl;
    		que[++tl] = i;
    	}
    
    #undef val
    }
    
    inline void solve( const int u, const int par ) {
    	f[u] = -LINF;
    	adj( virc, u, v ) solve( v, u );
    	if ( u <= n ) {
    		LL mx = book[u] ? 0 : -LINF, sx = -LINF;
    		adj( virc, u, v ) {
    			if ( LL d = f[v] + virc.len[e]; d > mx ) sx = mx, mx = d;
    			else if ( d > sx ) sx = d;
    		}
    		chkmax( ans, mx + sx ), f[u] = mx;
    	} else {
    		static std::vector<int> cir; cir.clear();
    
    		LL tmpp = pre[par]; pre[par] = 0;
    		cir.push_back( par );
    		adj( virc, u, v ) cir.push_back( v );
    		int sz = int( cir.size() );
    		cir.resize( sz << 1 );
    		rep ( i, 0, sz - 1 ) cir[sz + i] = cir[i];
    
    		contri( u, cir );
    		pre[par] = tmpp;
    
    		adj( virc, u, v ) chkmax( f[u], f[v] + virc.len[e] );
    	}
    	virc.head[u] = 0;
    }
    
    int main() {
    	n = rint(), m = rint();
    	rep ( i, 1, m ) {
    		int u = rint(), v = rint(), w = rint();
    		src( u, v, w ), src( v, u, w );
    	}
    
    	#ifdef RYBY
    		puts( "+++ +++ +++" );
    	#endif
    
    	vnode = n, buildCactus( 1, 0 );
    	dfc = 0, dep[1] = 1, initCactus( 1 );
    
    	#ifdef RYBY
    		puts( "--- --- ---" );
    	#endif
    
    	std::vector<int> vec;
    	for ( int q = rint(), k; q--; vec.clear() ) {
    		k = rint(), vec.resize( k );
    		rep ( i, 0, k - 1 ) book[vec[i] = rint()] = true;
    		buildVirCac( vec );
    		
    		ans = 0, solve( 1, 0 );
    		wint( ans ), putchar( '
    ' );
    
    		for ( int u: vec ) book[u] = false;
    	}
    
    	return 0;
    }
    
    
  • 相关阅读:
    简单的jQuery无缝向上滚动效果
    http://yuanma.wxb0.com/ 唯品源码网站
    vue.js 2.0 --- 安装node环境,webpack和脚手架
    记住密码后,密码框Password会自动带出数据
    http://ask.dcloud.net.cn/question/11695 nativeUI的使用(移动的)
    微信内置浏览器 如何小窗不全屏播放视频?
    webstrom快捷键
    6个html5页面适配iphone6的技巧
    rem的js
    docker打包容器成镜像文件、镜像文件加载到镜像
  • 原文地址:https://www.cnblogs.com/rainybunny/p/14696804.html
Copyright © 2011-2022 走看看