• 「SPOJ DYNALCA」Dynamic LCA


    Description

    有一个森林最初由 (n) 个互不相连的点构成

    你需要处理以下 (m) 次操作:

    link A B:添加从顶点A到B的边,使 (A) 成为 (B) 的子节点,其中保证 (A) 是一个根顶点,(A)(B) 在不同的树中。

    cut A:切断点 (A) 到其父节点的边,保证 (A) 是一个非根节点。

    lca A B:输出 (A)(B) 的最近共同祖先,保证 (A)(B) 在同一棵树中。

    Hint

    (1le n, mle 10^5)

    Solution

    看到加边和删边,不难想到用 ( exttt{Link-Cut Tree})

    但难点在于求 LCA。

    假设我们有这样一颗树,以 1 为根,并要求 lca 6 9

    JxK1UA.png

    先打通 6 到 根 的实链(红色边为实边),access(6)

    JxM9RP.png

    如果我们再 access(9),那么:

    JxM8Z4.png

    可以发现,原来有一条实边变虚(蓝色边)了,而这条虚边的父结点正是所求的最近公共祖先。

    结论,access(x) 后,再 access(y) 的过程中实变虚的最后一条边就是 LCA(x, y)

    具体做法,可以在 access 函数中加入返回值会好做一些。

    inline int access(int x) {
    	register int y = 0;
    	for (; x; x = fa[y = x]) splay(x), rc = y;
    	return y;
    }
    inline int LCA(int x, int y) {
    	return access(x), access(y);
    }
    

    注意,cut 操作不能 makrRoot,因为 LCA 这个东西是会受根结点的位置影响的,不可随意换根。而 link 由于 (x) 本来就是根,makeRoot 没有关系。

    Code

    /*
     * Author : _Wallace_
     * Source : https://www.cnblogs.com/-Wallace-/
     * Problem : SPOJ DYNALCA Dynamic LCA
     */
    #include <iostream>
    #include <string>
    
    using namespace std;
    const int N = 1e5 + 5;
    
    int ch[N][2], fa[N];
    bool rev[N];
    
    #define lc ch[x][0]
    #define rc ch[x][1]
    
    inline bool isRoot(int x) {
    	return x != ch[fa[x]][0] && x != ch[fa[x]][1];
    }
    inline int getc(int x) {
    	return x == ch[fa[x]][1];
    }
    
    inline void setRev(int x) {
    	swap(lc, rc), rev[x] ^= 1;
    }
    inline void pushdown(int x) {
    	if (rev[x]) {
    		if (lc) setRev(lc);
    		if (rc) setRev(rc);
    		rev[x] = 0;
    	}
    }
    inline void pushdownAll(int x) {
    	if (!isRoot(x)) pushdownAll(fa[x]);
    	pushdown(x);
    }
    
    inline void rotate(int x) {
    	int y = fa[x], z = fa[y];
    	int k = getc(x), w = ch[x][!k];
    	if (!isRoot(y)) ch[z][getc(y)] = x;
    	ch[x][!k] = y, ch[y][k] = w;
    	if (w) fa[w] = y;
    	fa[y] = x, fa[x] = z;
    }
    inline void splay(int x) {
    	pushdownAll(x);
    	for (register int y = fa[x]; !isRoot(x); rotate(x), y = fa[x])
    		if (!isRoot(y)) rotate(getc(x) != getc(y) ? x : y);
    }
    
    inline int access(int x) {
    	register int y = 0;
    	for (; x; x = fa[y = x]) splay(x), rc = y;
    	return y;
    }
    inline void makeRoot(int x) {
    	access(x), splay(x), setRev(x);
    }
    inline void link(int c, int f) {
    	makeRoot(c), fa[c] = f;
    }
    inline void cut(int x) {
    	access(x), splay(x), fa[lc] = 0, lc = 0;
    }
    inline int LCA(int x, int y) {
    	return access(x), access(y);
    }
    
    signed main() {
    	int n, q;
    	ios::sync_with_stdio(false);
    	cin >> n >> q;
    	
    	for (; q; --q) {
    		string cmd; int x, y;
    		cin >> cmd;
    		
    		if (cmd == "lca")
    			cin >> x >> y, cout << LCA(x, y) << endl;
    		if (cmd == "link")
    			cin >> x >> y, link(x, y);
    		if (cmd == "cut")
    			cin >> x, cut(x);
    	}
    	return 0;
    }
    
  • 相关阅读:
    jQuery Mobile-jquery Mobile 怎么用ajax提交表单
    Passing data between pages in JQuery Mobile | Ram's Blog
    jQuery Mobile Docs
    jquery mobile header title左对齐 button右对齐
    jquery mobile -role
    jQueryMobile$(document).ready 等价于?( jQuery mobi...
    HTML5,jQuery Mobile 可视化生成器 Tiggzi
    WebApi系列~开放的CORS,跨域资源访问对所有人开放
    WebApi系列~目录
    WebApi系列~基于单请求封装多请求的设计~请求的安全性设计与实现
  • 原文地址:https://www.cnblogs.com/-Wallace-/p/12819613.html
Copyright © 2020-2023  润新知