zoukankan      html  css  js  c++  java
  • Luogu2387 [NOI2014]魔法森林

    题目蓝链

    Description

    给你一个图,图上每条边都有两个权值(a, b)。经过一条边需要自身的属性(x, y)满足(a leq x, b leq y)。你现在要从(1)号点走到(n)号点,问你最小需要的自身属性(x, y)的和

    Solution

    我们可以考虑把边按(a_i)先进行排序,然后依次加入到图中。因为当边的(a_i)的最大值一定时,我们只需要最小化(b_i)即可。所以我们直接把(b_i)看成权值,然后用LCT去维护最小生成树就可以了

    在用LCT维护的时候,我们可以把每条边都对应建一个点,然后这个点的点权即为对应边的边权,其它点的点权为(0)。我们每添加一条边,需要先判断是否已经联通。若已联通,并且链上的最大值比当前添加的边的边权要大,则用当前边去替换

    Code

    #include <bits/stdc++.h>
    
    using namespace std;
    
    #define fst first
    #define snd second
    #define mp make_pair
    #define squ(x) ((LL)(x) * (x))
    #define debug(...) fprintf(stderr, __VA_ARGS__)
    
    typedef long long LL;
    typedef pair<int, int> pii;
    
    template<typename T> inline bool chkmax(T &a, const T &b) { return a < b ? a = b, 1 : 0; }
    template<typename T> inline bool chkmin(T &a, const T &b) { return a > b ? a = b, 1 : 0; }
    
    inline int read() {
    	int sum = 0, fg = 1; char c = getchar();
    	for (; !isdigit(c); c = getchar()) if (c == '-') fg = -1;
    	for (; isdigit(c); c = getchar()) sum = (sum << 3) + (sum << 1) + (c ^ 0x30);
    	return fg * sum;
    }
    
    const int maxn = 5e4 + 10;
    const int maxm = 1e5 + 10;
    const int inf = 5e4;
    
    int n, m;
    
    struct edge {
    	int x, y, a, b;
    	void input() { x = read(), y = read(), a = read(), b = read(); }
    	bool operator < (const edge &t) const { return a < t.a; }
    }e[maxm];
    
    namespace LCT {
    
    	struct node {
    		int son[2], f;
    		pii v, s; bool rev;
    	}A[maxn + maxm];
    #define ls(x) A[x].son[0]
    #define rs(x) A[x].son[1]
    #define fa(x) A[x].f
    
    	void push_up(int x) { A[x].s = max(A[x].v, max(A[ls(x)].s, A[rs(x)].s)); }
    	void push_down(int x) {
    		if (A[x].rev) {
    			swap(ls(x), rs(x));
    			A[ls(x)].rev ^= 1, A[rs(x)].rev ^= 1, A[x].rev = 0;
    		}
    	}
    
    	bool chkrt(int x) { return x != ls(fa(x)) && x != rs(fa(x)); }
    	bool chk(int x) { return x == rs(fa(x)); }
    	void link(int x, int y, int f) { fa(x) = y, A[y].son[f] = x; }
    	void rotate(int x) {
    		int f = fa(x), dx = chk(x), df = chk(f);
    		link(A[x].son[dx ^ 1], f, dx);
    		if (!chkrt(f)) link(x, fa(f), df); else fa(x) = fa(f);
    		link(f, x, dx ^ 1);
    		push_up(f), push_up(x);
    	}
    	void splay(int x) {
    		int _x = x;
    		static int S[maxn]; S[0] = 0;
    		while (!chkrt(x)) S[++S[0]] = x, x = fa(x);
    		S[++S[0]] = x, swap(x, _x);
    		for (int i = S[0]; i; i--) push_down(S[i]);
    		while (!chkrt(x)) {
    			int f = fa(x), dx = chk(x), df = chk(f);
    			if (chkrt(f)) rotate(x);
    			else if (dx == df) rotate(f), rotate(x);
    			else rotate(x), rotate(x);
    		}
    	}
    
    	void access(int x) { int _x = x; for (int lst = 0; x; lst = x, x = fa(x)) splay(x), rs(x) = lst, push_up(x); splay(_x); }
    	void mkrt(int x) { access(x), A[x].rev ^= 1; }
    	int getrt(int x) { access(x); while (ls(x)) push_down(x = ls(x)); return x; }
    	void split(int x, int y) { mkrt(x), access(y); }
    	void Link(int x, int y) { mkrt(x), fa(x) = y; }
    	void Cut(int x, int y) { split(x, y), fa(x) = 0, ls(y) = 0, push_up(y); }
    
    	pii get_max(int x, int y) { split(x, y); return A[y].s; }
    	void add(int x, int y, int v, int p1) {
    		if (getrt(x) == getrt(y)) {
    			pii res = get_max(x, y);
    			if (res.fst <= v) return;
    			int p2 = res.snd;
    			Cut(e[p2].x, p2 + n), Cut(p2 + n, e[p2].y);
    		}
    		Link(x, p1 + n), Link(p1 + n, y);
    		splay(p1 + n), A[p1 + n].v = mp(v, p1), push_up(p1 + n);
    	}
    	int check() {
    		if (getrt(1) == getrt(n)) return get_max(1, n).fst;
    		return inf << 2;
    	}
    }
    
    int main() {
    #ifdef xunzhen
    	freopen("tree.in", "r", stdin);
    	freopen("tree.out", "w", stdout);
    #endif
    
    	n = read(), m = read();
    	for (int i = 1; i <= m; i++) e[i].input();
    	sort(e + 1, e + m + 1);
    
    	int ans = inf << 2;
    	for (int i = 1, j = 1; i <= inf; i++) {
    		while (j <= m && e[j].a <= i) LCT::add(e[j].x, e[j].y, e[j].b, j), ++j;
    		chkmin(ans, i + LCT::check());
    	}
    
    	printf("%d
    ", ans < (inf << 2) ? ans : -1);
    
    	return 0;
    }
    
    19-2-11upd

    这题(Splay)函数里的(S)数组其实最好要开(maxn + maxm) 其实也无所谓

  • 相关阅读:
    vue 解析二维码
    自定义组件双向数据绑定,父v-model,子value用.$emit('input', newVal)
    懒加载组件
    float双飞布局
    [转]MySQL 8.0 Public Key Retrieval is not allowed 错误的解决方法
    【转】nginx产生【413 request entity too large】错误的原因与解决方法
    [其它]三维立体图简单入门含样例
    [其它] 美图看看 黑色皮肤下载不了
    vue element 表格内容文字太长加提示
    gitee webide怎么暂存文件(吐槽,gitee的产品真是吃屎的)
  • 原文地址:https://www.cnblogs.com/xunzhen/p/10322037.html
Copyright © 2011-2022 走看看