zoukankan      html  css  js  c++  java
  • 【题解】【雅礼集训 2017 Day5】远行 LOJ 6038 LCT

    Prelude

    快要THUWC了,练一练板子。

    传送到LOJ:o(TヘTo)


    Solution

    首先有一条定理。
    到树中任意一点的最远点一定是直径的两个端点之一。
    我也不会证反正大家都在用,似乎可以用反证法搞一搞?
    然后就是LCT和并查集随便做了。
    对于每个连通块,只需要保存这个连通块的直径的两个端点就可以了。
    然后合并两个连通块的时候更新一下。


    Code

    #include <cstring>
    #include <algorithm>
    #include <cstdio>
    #include <cctype>
    
    using namespace std;
    const int N = 300010;
    int _w;
    
    int read() {
    	int x = 0, ch;
    	while( isspace(ch = getchar()) );
    	do x = x * 10 + ch - '0';
    	while( isdigit(ch = getchar()) );
    	return x;
    }
    
    int type, n, q, lastans;
    
    namespace LCT {
    	struct Node {
    		int sz;
    		Node *ch[2], *pa, *pathpa;
    		bool rev;
    		Node() {
    			ch[0] = ch[1] = pa = pathpa = NULL;
    			sz = 1, rev = 0;
    		}
    		int relation() {
    			return this == pa->ch[0] ? 0 : 1;
    		}
    		Node *pushdown() {
    			if( rev ) {
    				rev = 0;
    				swap( ch[0], ch[1] );
    				if( ch[0] ) ch[0]->rev ^= 1;
    				if( ch[1] ) ch[1]->rev ^= 1;
    			}
    			return this;
    		}
    		Node *maintain() {
    			sz = 1;
    			if( ch[0] ) sz += ch[0]->sz;
    			if( ch[1] ) sz += ch[1]->sz;
    			return this;
    		}
    		Node *rotate() {
    			if( pa->pa ) pa->pa->pushdown();
    			pa->pushdown(), pushdown();
    			Node *old = pa;
    			int x = relation();
    			if( pa->pa ) pa->pa->ch[old->relation()] = this;
    			pa = pa->pa;
    			old->ch[x] = ch[x^1];
    			if( ch[x^1] ) ch[x^1]->pa = old;
    			ch[x^1] = old, old->pa = this;
    			swap(old->pathpa, pathpa);
    			return old->maintain(), maintain();
    		}
    		Node *splay() {
    			while( pa ) {
    				if( !pa->pa ) rotate();
    				else {
    					pa->pa->pushdown(), pa->pushdown();
    					if( relation() == pa->relation() )
    						pa->rotate(), rotate();
    					else rotate(), rotate();
    				}
    			}
    			return this;
    		}
    		Node *expose() {
    			Node *rc = splay()->pushdown()->ch[1];
    			if( rc ) {
    				ch[1] = rc->pa = NULL;
    				rc->pathpa = this;
    				maintain();
    			}
    			return this;
    		}
    		bool splice() {
    			if( !splay()->pathpa ) return false;
    			pathpa->expose()->ch[1] = this;
    			pa = pathpa, pathpa = NULL;
    			pa->maintain();
    			return true;
    		}
    		Node *access() {
    			expose();
    			while( splice() );
    			return this;
    		}
    		Node *evert() {
    			access()->rev ^= 1;
    			return this;
    		}
    	};
    	Node *rt[N];
    	void init() {
    		for( int i = 1; i <= n; ++i )
    			rt[i] = new Node;
    	}
    	void link( int u, int v ) {
    		rt[u]->evert()->pathpa = rt[v];
    	}
    	int query( int u, int v ) {
    		rt[u]->evert();
    		return rt[v]->access()->sz - 1;
    	}
    }
    
    namespace DSU {
    	int pa[N], du[N], dv[N];
    	void init() {
    		for( int i = 1; i <= n; ++i )
    			pa[i] = du[i] = dv[i] = i;
    	}
    	int find( int u ) {
    		return pa[u] == u ? u : pa[u] = find( pa[u] );
    	}
    	int uni( int u, int v ) {
    		u = find(u), v = find(v);
    		return pa[u] = v;
    	}
    }
    
    namespace Solve {
    	void init() {
    		DSU::init();
    		LCT::init();
    	}
    	void link( int u, int v ) {
    		using DSU::du;
    		using DSU::dv;
    		using DSU::find;
    		int u1 = du[find(u)], u2 = dv[find(u)];
    		int v1 = du[find(v)], v2 = dv[find(v)];
    		int w1 = LCT::query(u, u1) > LCT::query(u, u2) ? u1 : u2;
    		int w2 = LCT::query(v, v1) > LCT::query(v, v2) ? v1 : v2;
    		LCT::link(u, v);
    		int rt = DSU::uni(u, v);
    		int lenu = LCT::query(u1, u2);
    		int lenv = LCT::query(v1, v2);
    		int lenw = LCT::query(w1, w2);
    		// printf( "w1 = %d, w2 = %d, lenw = %d
    ", w1, w2, lenw );
    		if( lenu >= lenv && lenu >= lenw )
    			du[rt] = u1, dv[rt] = u2;
    		else if( lenv >= lenu && lenv >= lenw )
    			du[rt] = v1, dv[rt] = v2;
    		else
    			du[rt] = w1, dv[rt] = w2;
    		// printf( "du = %d, dv = %d
    ", du[rt], dv[rt] );
    	}
    	int query( int u ) {
    		using DSU::du;
    		using DSU::dv;
    		using DSU::find;
    		int u1 = du[find(u)], u2 = dv[find(u)];
    		return max( LCT::query(u, u1), LCT::query(u, u2) );
    	}
    }
    
    int main() {
    	type = read(), n = read(), q = read();
    	Solve::init();
    	while( q-- ) {
    		if( read() == 1 ) {
    			int u = read(), v = read();
    			u ^= type * lastans;
    			v ^= type * lastans;
    			Solve::link(u, v);
    		} else {
    			int u = read();
    			u ^= type * lastans;
    			printf( "%d
    ", lastans = Solve::query(u) );
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    JVM参数默认值列表
    垃圾回收G1日志解析
    《深入理解JAVA虚拟机》垃圾回收时为什么会停顿
    《深入理解JAVA虚拟机》JDK的垃圾收集算法
    什么才是技术?
    Lodash使用示例(比较全)
    MSCL超级工具类(C#),开发人员必备,开发利器
    刷新SqlServer数据库中所有的视图
    Sql Server 2014/2012/2008/2005 数据库还原出现 3154错误的解决办法
    C#中执行批处理文件(.bat),执行数据库相关操作
  • 原文地址:https://www.cnblogs.com/mlystdcall/p/8302660.html
Copyright © 2011-2022 走看看