zoukankan      html  css  js  c++  java
  • ☆ [NOI2014] 魔法森林 「LCT动态维护最小生成树」

    题目类型:(LCT)动态维护最小生成树

    传送门:>Here<

    题意:带权无向图,每条边有权值(a[i],b[i])。要求一条从(1)(N)的路径,使得这条路径上的(Max{a[i]}+Max{b[i]})最小

    解题思路

    (LCT)板子打错调试了半个小时……菜到不能再菜了……

    首先我们发现题目要求不是最小的和,而是最小的(Max{a[i]}+Max{b[i]})——都只取决于最大。因此我们可以联想,如果(Max{a})确定了,那么余下的就是用所有权值(a)不超过(Max{a})的边构建一棵以(b)为关键字的最小生成树。显然,这样一定能保证答案最优。

    因此我们可以考虑将所有边以(a)为关键字从小到大排序,由于是从小到大排序的,所以(Max{a})一定是最后加入生成树的这条边的(a)。余下的就是维护最小生成树了,那么直接用(LCT)进行动态维护就好了。如果(1,N)已经连通(利用(findroot)实现并查集),那么先(split),查询(Max{b}),加上目前为止最大的(Max{a})更新答案即可。

    非常巧妙~~

    反思

    要抓住题目所说的(Max)

    另外,(LCT)(pushup)中要更新三次,并且每次更新(mx[x])都有可能改变,因此要用(mx[x])而不是(x)

    Code

    /*By DennyQi 2018*/
    #include <cstdio>
    #include <queue>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    typedef long long ll;
    const int MAXN = 50010;
    const int MAXM = 100010;
    const int MAXS = MAXN + MAXM;
    const int INF = 1061109567;
    inline int Max(const int a, const int b){ return (a > b) ? a : b; }
    inline int Min(const int a, const int b){ return (a < b) ? a : b; }
    inline int read(){
        int x = 0; int w = 1; register char c = getchar();
        for(; c ^ '-' && (c < '0' || c > '9'); c = getchar());
        if(c == '-') w = -1, c = getchar();
        for(; c >= '0' && c <= '9'; c = getchar()) x = (x<<3) + (x<<1) + c - '0'; return x * w;
    }
    struct Edge{
    	int x,y,a,b;
    }e[MAXM];
    int N,M,ans(INF),maxa;
    int val[MAXS],mx[MAXS];
    struct LinkCutTree{
    	int ch[MAXS][2],fa[MAXS];
    	bool tag[MAXS];
    	inline bool rson(int f, int x){
    		return ch[f][1] == x;
    	}
    	inline bool isroot(int x){
    		return ch[fa[x]][0]!=x && ch[fa[x]][1]!=x;
    	}
    	inline void pushup(int x){
    		mx[x] = x;
    		if(val[mx[ch[x][0]]] > val[mx[x]]) mx[x] = mx[ch[x][0]];
    		if(val[mx[ch[x][1]]] > val[mx[x]]) mx[x] = mx[ch[x][1]];
    	}
    	inline void rotate(int x){
    		int f = fa[x], gf = fa[f];
    		bool p = rson(f,x), q = !p;
    		if(!isroot(f)) ch[gf][rson(gf,f)] = x; fa[x] = gf;
    		ch[f][p] = ch[x][q], fa[ch[x][q]] = f;
    		ch[x][q] = f, fa[f] = x;
    		pushup(f), pushup(x);
    	}
    	void reverse(int x){
    		if(!isroot(x)) reverse(fa[x]);
    		if(!tag[x]) return;
    		tag[x] = 0;
    		swap(ch[x][0], ch[x][1]);
    		tag[ch[x][0]] ^= 1, tag[ch[x][1]] ^= 1;
    	}
    	inline void splay(int x){
    		for(reverse(x); !isroot(x); rotate(x)){
    			if(isroot(fa[x])){ rotate(x); break; }
    			if(rson(fa[fa[x]],fa[x]) ^ rson(fa[x],x)) rotate(x); else rotate(fa[x]);
    		}
    	}
    	inline void access(int x){
    		for(int y = 0; x; y=x, x = fa[x]) splay(x), ch[x][1] = y, pushup(x);
    	}
    	inline void mroot(int x){
    		access(x), splay(x), tag[x] ^= 1;
    	}
    	inline int findroot(int x){
    		access(x), splay(x);
    		while(ch[x][0]) x = ch[x][0];
    		return x;
    	}
    	inline void split(int x, int y){
    		mroot(x);
    		access(y);
    		splay(y);
    	}
    	inline void link(int x, int y){
    		mroot(x);
    		fa[x] = y;
    	}
    	inline void cut(int x, int y){
    		split(x,y);
    		if(ch[y][0] != x || ch[x][1]) return;
    		ch[y][0] = fa[x] = 0;
    	}
    }qxz;
    inline bool cmp(const Edge& a, const Edge& b){
    	return a.a < b.a;
    }
    int main(){
    //	freopen(".in","r",stdin);
    	N = read(), M = read();
    	for(int i = 1; i <= M; ++i){
    		e[i].x = read(), e[i].y = read(), e[i].a = read(), e[i].b = read();
    	}
    	sort(e+1, e+M+1, cmp);
    	for(int i = 1; i <= M; ++i){
    		val[N+i] = e[i].b;
    		if(qxz.findroot(e[i].x) != qxz.findroot(e[i].y)){
    			qxz.link(e[i].x, N+i);
    			qxz.link(e[i].y, N+i);
    			maxa = e[i].a;
    		}
    		else{
    			qxz.split(e[i].x, e[i].y);
    			if(val[mx[e[i].y]] > e[i].b){
    				int temp = mx[e[i].y]-N;
    				qxz.cut(e[temp].x, temp+N);
    				qxz.cut(e[temp].y, temp+N);
    				qxz.link(e[i].x, N+i);
    				qxz.link(e[i].y, N+i);
    				maxa = e[i].a;
    			}
    		}
    		if(qxz.findroot(1) == qxz.findroot(N)){
    			qxz.split(1, N);
    			ans = Min(ans, maxa + val[mx[N]]);
    		}
    	}
    	if(ans == INF) printf("-1");
    	else printf("%d", ans);
    	return 0;
    }
    
  • 相关阅读:
    非foreach情况下取某一节点的position()
    MorningSale 介绍
    XSLT中的内容自动换列
    十年相伴一首歌
    Navicat的强大自动定时备份
    Xshell6评估期已过的解决方法
    Ext JS继承: 关于object, constructor和prototype
    WCF+Silverlight 异常处理
    Adding/removing fields and columns drag & drop bug's fix
    WCF部署至IIS问题二则
  • 原文地址:https://www.cnblogs.com/qixingzhi/p/9735609.html
Copyright © 2011-2022 走看看