zoukankan      html  css  js  c++  java
  • 曼哈顿距离最小生成树 codechef Dragonstone

    曼哈顿距离最小生成树

    codechef Dragonstone

    首先,对于每一个点来说有用的边只有它向它通过 x=0,y=0,y=x,y=-x 切出来的八个平面的最近点。

    证明 我不会

    反正当结论记住就行了

    然后我们就只需要考虑右上这个区间的点(因为看起来最好做)

    其他的区间可以通过坐标变换到这个区间,并且因为边是双向的,可以只考虑y=-x切出来的右上的这四个区间。

    对于一个点 $ B(x_1,y_1) $ 和这里的点 $ A(x_0,y_0) $ B是合法的当且仅当 $ x_1 > x_0 , y_1 > y_0 , x_1-x_0 leq y_1 - y_0 $

    再推一下,发现 $ y_1 > y_0 $ 这个条件然并卵,因为第三个条件和第一个条件已经限制了它

    所以我们可以看成这两个式子 $ x_1 > x_0 , x_1 - y_1 leq x_0 - y_0 $

    同时,需要满足 $ x_1 + y_1 $ 尽量小

    把 $ x_1 + y_1 $ 当成权值加入线段树,位置在 $ x_1 - y_1 $ 就好了

    差需要离散化

    别忘多组。。wa了好多次。。

    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #include<cstdio>
    #include<vector>
    using namespace std;
    #define int long long
    #define MAXN 800006
    #define pb push_back
    #define pii pair<int,int>
    #define fi first
    #define se second
    #define mp make_pair
    #define inf 0x3f3f3f3f3f3f3f3f
    int n , q;
    namespace SGT {
    	pii T[MAXN << 2];
    	void pushup( int rt ) {
    		T[rt] = min( T[rt << 1] , T[rt << 1 | 1] );
    	}
    	void build( int rt , int l , int r ) {
    		T[rt] = mp( inf , inf );
    		if( l == r ) return; 
    		int m = l + r >> 1;
    		build( rt << 1 , l , m ) , build( rt << 1 | 1 , m + 1 , r );
    	}
    	void mdfy( int rt , int l , int r , int p , pii c ) {
    		if( l == r && p == l ) { T[rt] = min( T[rt] , c ); return; }
    		int m = l + r >> 1;
    		if( p <= m ) mdfy( rt << 1 , l , m , p , c );
    		else mdfy( rt << 1 | 1 , m + 1 , r , p , c );
    		pushup( rt );
    	}
    	pii que( int rt , int l , int r , int L , int R ) {
    		if( L <= l && R >= r ) return T[rt];
    		int m = l + r >> 1; pii res = mp( inf , inf );
    		if( L <= m ) res = min( res , que( rt << 1 , l , m , L , R ) );
    		if( R > m ) res = min( res , que( rt << 1 | 1 , m + 1 , r , L , R ) );
    		return res;
    	}
    }
    #define mx 600000
    struct point{
    	int x , y , id;
    } P[MAXN] ;
    bool cmp( point x , point y ) {
    	return x.x == y.x ? x.y > y.y : x.x > y.x;
    }
    int A[MAXN] , a[MAXN];
    struct edge{
    	int u , v , w;
    } E[MAXN] ; int ecn;
    void doit(  ) {
    	sort( P + 1 , P + 1 + n , cmp );
    	for( int i = 1 ; i <= n ; ++ i ) A[i] = P[i].x - P[i].y;
    	sort( A + 1 , A + 1 + n );
    	int sz = unique( A + 1 , A + 1 + n ) - A - 1;
    	for( int i = 1 ; i <= n ; ++ i ) a[i] = lower_bound( A + 1 , A + 1 + sz , P[i].x - P[i].y ) - A ;
    	SGT::build( 1 , 1 , mx );
    	pii res = mp( 0 , 0 );
    	for( int i = 1 ; i <= n ; ++ i ) {
    		pii fd = SGT::que( 1 , 1 , mx , 1 , a[i] );
    		if( fd.se != 0x3f3f3f3f3f3f3f3f ) 
    			E[++ecn] = ( edge ) { P[i].id , fd.se , - P[i].x - P[i].y + fd.fi };
    		SGT::mdfy( 1 , 1 , mx , a[i] , mp( P[i].x + P[i].y , P[i].id ) );
    	}
    }
    bool cmpp( edge a , edge b ) {
    	return a.w < b.w;
    }
    int fa[MAXN];
    int find( int x ) {
    	return x == fa[x] ? x : fa[x] = find( fa[x] );
    }
    
    namespace tree {
    	int head[MAXN] , nex[MAXN] , to[MAXN] , wto[MAXN] , cn;
    	void ade( int u , int v , int w ) {
    		nex[++cn] = head[u] , to[cn] = v , wto[cn] = w , head[u] = cn;
    	}
    	#define MAXK 20
    	int G[MAXN][MAXK][2];
    	int dep[MAXN];
    	void init(  ) {
    		dep[1] = 0;
    		memset( head , 0 , sizeof head );
    		memset( G , 0 , sizeof G );
    		cn = 0;
    	}
    	void dfs( int u , int fa ) {
    		dep[u] = dep[fa] + 1;
    		for( int i = head[u] ; i ; i = nex[i] ) {
    			int v = to[i];
    			if( v == fa ) continue;
    			G[v][0][0] = u , G[v][0][1] = wto[i];
    			for(int j = 1 ; j < 20 ; ++ j)
                    if(G[G[v][j - 1][0]][j - 1][0])
                        G[v][j][0] = G[G[v][j-1][0]][j-1][0],G[v][j][1] = max(G[v][j-1][1],G[G[v][j-1][0]][j-1][1]);
                    else break;
    			dfs( v , u );
    		}
    	}
    	int que( int u , int v ) {
    		if( dep[u] < dep[v] ) swap( u , v );
    		int suml = -inf , sumr = -inf;
    		if( dep[u] != dep[v] )
    			for( int k = MAXK - 1 ; k >= 0 ; -- k )
    				if( dep[G[u][k][0]] >= dep[v] )
    					suml = max( suml , G[u][k][1] ) , u = G[u][k][0];
    		if( u == v ) return max( suml , sumr );
    		for( int k = MAXK - 1 ; k >= 0 ; -- k )
    			if( G[u][k][0] != G[v][k][0] )
    				suml = max( suml , G[u][k][1] ) , sumr = max( sumr , G[v][k][1] ),
    				u = G[u][k][0] , v = G[v][k][0];
    		suml = max( suml , G[u][0][1] ) , sumr = max( sumr , G[v][0][1] );
    		return max( suml , sumr );
    	}
    }
    
    signed main( ) {
    	freopen("fuck.in","r",stdin);
    	int T;cin >> T;
    	while( T-- ) {
    		cin >> n;
    		ecn = 0;
    		for( int i = 1 , u , v ; i <= n ; ++ i ) 
    			scanf("%lld%lld",&P[i].x,&P[i].y) , P[i].id = i;
    		doit(  );
    		for( int i = 1 ; i <= n ; ++ i ) swap( P[i].x , P[i].y );
    		doit(  );
    		for( int i = 1 ; i <= n ; ++ i ) P[i].x = -P[i].x;
    		doit(  );
    		for( int i = 1 ; i <= n ; ++ i ) swap( P[i].x , P[i].y );
    		doit(  );
    		sort( E + 1 , E + 1 + ecn , cmpp );
    		tree::init(  );
    		for( int i = 1 ; i <= n ; ++ i ) fa[i] = i;
    		for( int i = 1 ; i <= ecn ; ++ i ) if( find( E[i].u ) != find( E[i].v ) )
    			fa[find( E[i].u )] = find( E[i].v ) ,
    			tree::ade( E[i].u , E[i].v , E[i].w ) , 
    			tree::ade( E[i].v , E[i].u , E[i].w );
    		tree::dfs( 1 , 1 );
    		cin >> q;
    		int u , v;
    		while( q-- ) {
    			scanf("%lld%lld",&u,&v);
    			printf("%lld
    ",tree::que( u , v ));
    		}
    	}
    }
    
  • 相关阅读:
    VS2017 C# winform 项目使用 sqlite (二)
    VS2017 C# winform 项目使用 sqlite (一)
    JS权威指南笔记(171页)-this关键字的作用域
    量化交易之下单函数和context对象
    量化交易策略基本框架
    初始量化交易
    金融量化之Tushare模块
    Python之基础算法介绍
    数据分析之Matplotlib和机器学习基础
    数据分析之Pandas
  • 原文地址:https://www.cnblogs.com/yijan/p/dragonstone.html
Copyright © 2011-2022 走看看