zoukankan      html  css  js  c++  java
  • P4299 首都

    P4299 首都

    容易发现,这个难啊,要动态维护重心,有一个 (color {black} { ext {n}} color {red} { ext{aive}}) 的想法就是直接 (O (n log^2 n)) 启发式合并,但是我们的 (color {black} { ext {Y}} color {red} { ext {outh518}}) 大佬直接利用LCT爆切。

    可以发现的是,如果两个树合并,那么他们的重心必定在原来两个树重心的路径上。那么我们其实可以合并后split一下利用splay来跳,可以快速得到重心的位置,这个复杂度可以做到 (O(n log n))

    /*
    	Name:
    	Author: Gensokyo_Alice
    	Date:
    	Description:
    */
    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <cstdlib>
    #include <cstdio>
    #include <vector>
    #include <queue>
    #include <stack>
    #include <cmath>
    #include <ctime>
    #include <map>
    #include <set>
    
    using namespace std;
    
    typedef long long ll;
    const ll MAXN = (1LL << 20) + 10, INF = 0x3f3f3f3f3f3f3f3f;
    
    ll N, M, ans, r[MAXN], c[MAXN][2], fa[MAXN], st[MAXN], s[MAXN], si[MAXN], f[MAXN];
    
    void link(ll, ll);
    void access(ll);
    void split(ll, ll);
    void cut(ll, ll);
    void makeroot(ll);
    ll findroot(ll);
    void splay(ll);
    void rotate(ll);
    ll find_(ll);
    ll updata(ll);
    void pushup(ll);
    void pushr(ll);
    void pushdown(ll);
    
    int main() {
    	scanf("%lld%lld", &N, &M);
    	for (ll i = 1; i <= N; i++) s[i] = 1, f[i] = i, ans ^= i;
    	for (ll i = 1, x, y; i <= M; i++) {
    		char s[10]; 
    		scanf("%s", s+1);
    		if (s[1] == 'A') {
    			scanf("%lld%lld", &x, &y);
    			link(x, y);
    			x = find_(x), y = find_(y);
    			split(x, y);
    			ll z = updata(y);
    			ans = ans ^ x ^ y ^ z;
    			f[x] = f[y] = f[z] = z;
    		} else if (s[1] == 'Q') {
    			scanf("%lld", &x);
    			printf("%lld
    ", find_(x));
    		} else if (s[1] == 'X') printf("%lld
    ", ans);
    	}
        return 0;
    }
    
    void access(ll x) {for (ll y = 0; x; y = x, x = fa[x]) splay(x), si[x] += s[c[x][1]], si[x] -= s[c[x][1] = y], pushup(x);}
    void makeroot(ll x) {access(x); splay(x); pushr(x);}
    void link(ll x, ll y) {split(x, y); if (findroot(y) != x) si[fa[x] = y] += s[x];}
    void split(ll x, ll y) {makeroot(x); access(y); splay(y);} 
    void cut(ll x, ll y) {split(x, y); if (findroot(y) != x || fa[y] != x || c[y][0]) return; fa[y] = c[x][1] = 0;}
    void pushr(ll x) {swap(c[x][0], c[x][1]); r[x] ^= 1;}
    void pushup(ll x) {s[x] = s[c[x][0]] + s[c[x][1]] + si[x] + 1;}
    void pushdown(ll x) {if (r[x]) {if (c[x][0]) pushr(c[x][0]); if (c[x][1]) pushr(c[x][1]);} r[x] = 0;}
    bool nroot(ll x) {return c[fa[x]][0] == x || c[fa[x]][1] == x;}
    ll findroot(ll x) {access(x); splay(x); while (c[x][0]) x = c[x][0]; return x;}
    void splay(ll x) {
    	ll y = x, z = 0; st[++z] = y;
    	while (nroot(y)) st[++z] = (y = fa[y]); while (z) pushdown(st[z--]);
    	while (nroot(x)) {
    		y = fa[x], z = fa[y];
    		if (nroot(y)) rotate(((c[y][0] == x) ^ (c[z][0] == y)) ? x : y);
    		rotate(x);
    	}
    	pushup(x);
    }
    void rotate(ll x) {
    	ll y = fa[x], z = fa[y], k = c[y][1] == x, w = c[x][!k];
    	if (nroot(y)) c[z][c[z][1] == y] = x; c[x][!k] = y; c[y][k] = w;
    	if (w) fa[w] = y; fa[y] = x; fa[x] = z;
    	pushup(y);	
    }
    
    ll find_(ll x) {return f[x] == x ? x : f[x] = find_(f[x]);}
    ll updata(ll node) {
    	ll l, r, ji = s[node] & 1, sum = s[node] >> 1, lsum = 0, rsum = 0, nowl, nowr, tar = INF;
    	while (node) {
    		pushdown(node);
    		nowl = s[l = c[node][0]] + lsum, nowr = s[r = c[node][1]] + rsum;
    		if (nowl <= sum && nowr <= sum) {
    			if (ji & 1) {tar = node; break;}
    			else if (tar > node) tar = node;
    		}
    		if (nowl < nowr) lsum += s[l] + si[node] + 1, node = r;
    		else rsum += s[r] + si[node] + 1, node = l;
    	}
    	splay(tar);
    	return tar;
    }
    
    
  • 相关阅读:
    Online Object Tracking: A Benchmark 翻译
    线性判别分析(Linear Discriminant Analysis)转载
    网址大全
    计算机视觉学习方法
    计算机视觉顶级期刊会议
    爬取淘宝小姐姐头像
    CSP201512-03画图 90分
    二叉树的基本操作之二叉排序树
    sort排序实现
    冒泡排序实现
  • 原文地址:https://www.cnblogs.com/Gensokyo-Alice/p/14236299.html
Copyright © 2011-2022 走看看