• 3754. 【NOI2014】魔法森林(LCT)


    Problem

    给定一个(n)个结点,(m)条边的的无向图,每条边有两个权值(ai,bi).

    现在从(1)出发,要到达(n),每次只能沿着(aile A)(bile B)的边走,求(min(A+B)).

    (nle 5*10^4,mle 2*10^5)

    Solution

    经典的LCT题,拆边权为点权就没了.

    顺便说一下LCT这个神奇的数据结构。因为姿势有限,暂且不讨论它的势能分析。

    定义

    LCT = splay + 虚实剖分

    每个节点有 至多一条 实边连向儿子, 实边 相连,构成了一条 实链.

    对于每条实链用一个 splay 去维护,关键字就是在原树当中以 根节点 为基准的 深度

    Access

    最重要的操作.

    Access(N)定义为改变从(N)到根节点这一段路的每个节点的实边.

    在代码中用这个过程实现:

    void Access(int x) {
    	for (int y = 0; x ; y = x, x = fa[x])
    		splay(x), tr[x][1] = y, update(x);
    }
    
    Makeroot

    定义为把某个点设为根,用这个过程去实现:

    void Makeroot(int x) {
    	Access(x);
    	splay(x);
    	reverse(x);
    }
    
    Link,cut

    就显得很简单了

    void link(int x,int y) {
    	Makeroot(x);
    	fa[x] = y;
    }
    
    void cut(int x, int y) {
    	Makeroot(x);
    	Access(y);
    	splay(y);
    	fa[tr[y][0]] = 0, tr[y][0] = 0;
    	update(y);
    }
    
    注意

    rotate的打法必须要记住这样打:

    void rotate(int x) {
    	int y = fa[x], t = son(x);
    	if (!Rt(y)) tr[fa[y]][son(y)] = x; // 这里一定要注意!!!
    	if (tr[x][1 - t]) fa[tr[x][1 - t]] = y;
    	fa[x] = fa[y], fa[y] = x, tr[y][t] = tr[x][1 - t], tr[x][1 - t] = y;
    	update(y), update(x); 
    }
    
    
    Code
    #include <bits/stdc++.h>
    
    #define F(i, a, b) for (int i = a; i <= b; i ++)
    #define ls tr[x][0]
    #define rs tr[x][1]
    
    const int N = 2e5 + 10;
    
    using namespace std;
    
    int n, m, x, y, Ans, RT;
    int v[N], tr[N][2], fa[N], rev[N], d[N], pt[N], fat[N];
    struct edge {
    	int x, y, a, b;
    	friend bool operator < (edge a, edge b) { return a.a < b.a; }
    } e[N];
    
    int son(int x) { return tr[fa[x]][1] == x; }
    bool Rt(int x) { return tr[fa[x]][son(x)] ^ x; }
    
    void reverse(int x) { swap(ls, rs), rev[x] ^= 1; }
    void push(int x) {
    	if (!rev[x]) return;
    	reverse(ls), reverse(rs), rev[x] = 0;
    }
    
    void update(int x) {
    	pt[x] = x;
    	if (v[pt[ls]] > v[pt[x]]) pt[x] = pt[ls];
    	if (v[pt[rs]] > v[pt[x]]) pt[x] = pt[rs];
    }
    
    void rotate(int x) {
    	int y = fa[x], t = son(x);
    	if (!Rt(y)) tr[fa[y]][son(y)] = x;
    	if (tr[x][1 - t]) fa[tr[x][1 - t]] = y;
    	fa[x] = fa[y], fa[y] = x, tr[y][t] = tr[x][1 - t], tr[x][1 - t] = y;
    	update(y), update(x); 
    }
    
    void clear(int x) {
    	d[++ d[0]] = x;
    	while (!Rt(x)) d[++ d[0]] = x = fa[x];
    	while (d[0]) push(d[d[0] --]);
    }
    
    void splay(int x) {
    	clear(x);
    	for (; !Rt(x); rotate(x))
    		if (!Rt(fa[x])) rotate(son(x) == son(fa[x]) ? fa[x] : x);
    }
    
    void Access(int x) {
    	for (int y = 0; x ; y = x, x = fa[x])
    		splay(x), rs = y, update(x);
    }
    
    void Makeroot(int x) { Access(x), splay(x), reverse(x); }
    void link(int x, int y) { Makeroot(x), fa[x] = y; }
    void cut(int x, int y) { Makeroot(x); Access(y); splay(y); fa[tr[y][0]] = 0, tr[y][0] = 0; update(y); }
    
    int Solve(int x, int y) {
    	Makeroot(x); Access(y), splay(y);
    	return pt[y];
    }
    int get(int x) { return !fat[x] ? x : fat[x] = get(fat[x]); }
    
    int main() {
    	scanf("%d%d", &n, &m);
    	F(i, 1, m) {
    		scanf("%d%d%d%d", &e[i].x, &e[i].y, &e[i].a, &e[i].b);
    		if (e[i].x == e[i].y) i --, m --;
    	}
    
    	sort(e + 1, e + m + 1);
    
    	Ans = 1e9;
    	F(i, 1, m) {
    		x = e[i].x, y = e[i].y, v[i + n] = e[i].b;
    		int xx = get(x), yy = get(y);
    		if (xx ^ yy) fat[xx] = yy; else {
    			int pos = Solve(x, y);
    			if (v[pos] <= e[i].b) continue;
    			cut(e[pos - n].x, pos), cut(pos, e[pos - n].y);
    		}
    		link(x, i + n), link(i + n, y);
    		if (get(1) == get(n))
    			Ans = min(Ans, e[i].a + v[Solve(1, n)]);
    	}
    	printf("%d
    ", Ans == 1e9 ? - 1 : Ans);
    }
    
  • 相关阅读:
    超简单解释TCP、UDP、HTTP
    亲身经历面试题总结
    面试最让你手足无措的一个问题:你的系统如何支撑高并发?
    什么是hadoop,hadoop可以做什么
    在.net Core中如何使用HTML5上传视频
    2018很废的一年
    SQL合集
    ASP.NET CORE 基础配置、Linux发包
    SQL获取本周,上周,本月,上月的开始时间和结束时间
    C# net Emgu.CV.World 人脸识别 根据照片将人脸抠图出来。
  • 原文地址:https://www.cnblogs.com/Pro-king/p/10760435.html
Copyright © 2020-2023  润新知