快要THUWC了,練一練板子。git
傳送到LOJ:o(TヘTo)this
首先有一條定理。
到樹中任意一點的最遠點必定是直徑的兩個端點之一。
我也不會證反正你們都在用,彷佛能夠用反證法搞一搞?
而後就是LCT和並查集隨便作了。
對於每一個連通塊,只須要保存這個連通塊的直徑的兩個端點就能夠了。
而後合併兩個連通塊的時候更新一下。spa
#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\n", 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\n", 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\n", lastans = Solve::query(u) ); } } return 0; }