zoukankan      html  css  js  c++  java
  • 【ybt金牌导航5-4-3】【luogu P2387】魔法森林

    魔法森林

    题目链接:ybt金牌导航5-4-3 / luogu P2387

    题目大意

    有一个无向图,每个边有 AB 两种权值。
    要找一条从 1 到 n 的路径,使得路径上的边 A 权值最大值加 B 权值最大值最小。
    如果无法到达输出 -1。

    思路

    首先看到两个权值的最大最小,然后每个范围都不是很大。

    我们考虑枚举一个的最大值,然后把边按哪个排序,构出每个时刻的图,然后让另一个的最大值最小。
    那接着问题就是如果让最大值最小了。
    发现要不断的加边然后维护这个值,我们想到 LCT。
    但是考虑权值在边上,而且它不是树。
    我们考虑用这么一个搞法,它边有权,我们就把边看做 LCT 的点。
    然后拿并查集维护点之间的连通性,如果之前不连通,就正常搞。
    否则就 LCT 提取出那条链,如果它的最大值大于你的现在这条,肯定就是换(把之前的删掉再加边),否则就不管。

    然后就 LCT 维护一下就可以了。

    代码

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define INF 0x3f3f3f3f3f3f3f3f
    
    using namespace std;
    
    struct line {
    	int x, y, a, b;
    }a[150001];
    int n, m, le[150001], KK, ans = INF;
    int nowa, fa[150001], dist[150001];
    int l[150001], r[150001], pl[150001];
    int fath[150001];
    bool lzs[150001], ch;
    
    bool cmp(line x, line y) {//按a排序
    	return x.a < y.a;
    }
    
    bool nrt(int x) {//LCT
    	return l[fa[x]] == x || r[fa[x]] == x;
    }
    
    bool ls(int x) {
    	return l[fa[x]] == x;
    }
    
    void up(int x) {
    	pl[x] = x;//记得要清空,并算自己的
    	if (l[x] && dist[pl[x]] < dist[pl[l[x]]]) pl[x] = pl[l[x]];
    	if (r[x] && dist[pl[x]] < dist[pl[r[x]]]) pl[x] = pl[r[x]];
    }
    
    void downs(int x) {
    	swap(l[x], r[x]);
    	lzs[x] ^= 1;
    }
    
    void down(int x) {
    	if (lzs[x]) {
    		if (l[x]) downs(l[x]);
    		if (r[x]) downs(r[x]);
    		lzs[x] = 0;
    	}
    }
    
    void down_line(int x) {
    	if (nrt(x)) down_line(fa[x]);
    	down(x);
    }
    
    void rotate(int x) {
    	int y = fa[x];
    	int z = fa[y];
    	int b = (ls(x) ? r[x] : l[x]);
    	if (z && nrt(y)) (ls(y) ? l[z] : r[z]) = x;
    	if (ls(x)) r[x] = y, l[y] = b;
    		else l[x] = y, r[y] = b;
    	fa[x] = z;
    	fa[y] = x;
    	if (b) fa[b] = y;
    	up(y);
    }
    
    void Splay(int x) {
    	down_line(x);
    	
    	while (nrt(x)) {
    		if (nrt(fa[x])) {
    			if (ls(x) == ls(fa[x])) rotate(fa[x]);
    				else rotate(x);
    		}
    		rotate(x);
    	}
    	
    	up(x);
    }
    
    void access(int x) {
    	int lst = 0;
    	for (; x; x = fa[x]) {
    		Splay(x);
    		
    		r[x] = lst;
    		up(x);
    		lst = x;
    	}
    }
    
    void make_root(int x) {
    	access(x);
    	Splay(x);
    	downs(x);
    }
    
    int find_root(int x) {
    	access(x);
    	Splay(x);
    	while (l[x]) {
    		down(x);
    		x = l[x];
    	}
    	Splay(x);
    	return x;
    }
    
    void cut(int x, int y) {
    	make_root(x);
    	access(y);
    	Splay(y);
    	l[y] = 0;
    	fa[x] = 0;
    	up(y);
    }
    
    void link(int x, int y) {
    	make_root(x);
    	if (find_root(y) != x) {
    		fa[x] = y;
    	}
    }
    
    int split(int x, int y) {
    	make_root(x);
    	access(y);
    	Splay(y);
    	return y;
    }
    
    int query(int x, int y) {
    	x = split(x, y);
    	return dist[pl[x]];
    }
    
    int find(int now) {//并查集维护连通
    	if (fath[now] == now) return now;
    	return fath[now] = find(fath[now]);
    }
    
    void connect(int x, int y) {
    	int X = find(x);
    	int Y = find(y);
    	fath[X] = Y;
    }
    
    bool connect_ck(int x, int y) {
    	int X = find(x);
    	int Y = find(y);
    	return X == Y;
    }
    
    int main() {
    	scanf("%d %d", &n, &m);
    	for (int i = 1; i <= m; i++) {
    		scanf("%d %d %d %d", &a[i].x, &a[i].y, &a[i].a, &a[i].b);
    		if (a[i].x == a[i].y) i--, m--;
    	}
    	
    	sort(a + 1, a + m + 1, cmp);
    	for (int i = 1; i <= n + m; i++)
    		pl[i] = i, fath[i] = i;
    	for (int i = n + 1; i <= n + m; i++)
    		dist[i] = a[i - n].b;
    	
    	for (int i = 1; i <= 50000; i++) {//枚举最大的 a
    		ch = 0;
    		while (nowa < m && a[nowa + 1].a <= i) {//逐渐加边
    			nowa++;
    			if (connect_ck(a[nowa].x, a[nowa].y)) {//加边会出环,判断哪个更优
    				int w = pl[split(a[nowa].x, a[nowa].y)];
    				if (dist[w] > a[nowa].b) {//更优(把之前的边删了,再连)
    					cut(a[w - n].x, w);
    					cut(w, a[w - n].y);
    					link(a[nowa].x, n + nowa);
    					link(n + nowa, a[nowa].y);
    				}
    			}
    			else link(a[nowa].x, n + nowa), link(n + nowa, a[nowa].y), connect(a[nowa].x, a[nowa].y);//普通连边
    			
    			ch = 1;
    		}
    		if (ch && connect_ck(1, n)) {
    			ans = min(ans, i + query(1, n));
    			if (nowa == m) break;
    		}
    	}
    	
    	if (ans == (int)INF) printf("-1");
    		else printf("%d", ans);
    	
    	return 0;
    }
    
  • 相关阅读:
    ASP.net MVC 构建layui管理后台(构造基础仓储)<1>
    ASP.net MVC 构建layui管理后台(整体效果)
    搭建私有 Nuget 服务器教程(1)
    SSAS数据集Cube不存在或者尚未处理
    浅谈MDX处理空值NULL及格式化结果
    Zoey.Dapper--Dapper扩展之把SQL语句放到文件中
    Polly每次重试执行不同的操作
    Exceptionless应用--自定义插件
    Fiddler开启Https的时候出现unable to configure windows to trust Fiddler Root certificate问题
    ASP.NET Core 中的配置
  • 原文地址:https://www.cnblogs.com/Sakura-TJH/p/YBT_JPDH_5-4-3.html
Copyright © 2011-2022 走看看