• cogs1685 【NOI2014】魔法森林 Link-Cut Tree


    LCT练手好题啊。
    SPFA的做♂FA是把边按照a排序,然后加一条权值为b的边跑SPFA,不断更新答案。很好的做♂FA,但复杂度无♂FA保证。
    LCT的做♂FA类似,也是把边按照a排序,然后也是加一条权值为b的边,动态维护最小生成树。
    然后赋边权的方♂FA是新建一个点表示边,原来点的权值为0,边的权值还是边的权值,剩下的都一样辣。

    // It is made by XZZ
    #include<cstdio>
    #include<algorithm>
    #define il inline
    #define rg register
    #define vd void
    #define sta static
    typedef int mainint;
    #define int long long
    il int gi(){
    	rg int x=0,f=1;rg char ch=getchar();
    	while(ch<'0'||ch>'9')f=ch=='-'?-1:f,ch=getchar();
    	while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    	return x*f;
    }
    const int maxn=100001,maxm=100001;
    namespace LCT{
    	int ch[maxn][2],fa[maxn],w[maxn],mx[maxn],A[maxn],B[maxn];bool rev[maxn];
    	int index;
    	il vd down(const int&x){if(rev[x])std::swap(ch[x][0],ch[x][1]),rev[ch[x][0]]^=1,rev[ch[x][1]]^=1,rev[x]=0;}
    	il vd upd(const int&x){
    		mx[x]=x;
    		if(w[mx[x]]<w[mx[ch[x][0]]])mx[x]=mx[ch[x][0]];
    		if(w[mx[x]]<w[mx[ch[x][1]]])mx[x]=mx[ch[x][1]];
    	}
    	il bool isrt(const int&x){return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;}
    	il vd rotate(const int&x){
    		sta int y,z,o;y=fa[x],z=fa[y],o=x==ch[y][1];
    		if(!isrt(y))ch[z][y==ch[z][1]]=x;fa[x]=z;
    		ch[y][o]=ch[x][!o];fa[ch[x][!o]]=y;
    		fa[y]=x;ch[x][!o]=y;
    		upd(y);
    	}
    	il vd splay(const int&x){
    		sta int stk[maxn],top;stk[top=1]=x;
    		for(rg int i=x;!isrt(i);i=fa[i])stk[++top]=fa[i];
    		while(top)down(stk[top--]);
    		for(rg int y=fa[x],z=fa[y];!isrt(x);rotate(x),y=fa[x],z=fa[y])
    			if(!isrt(y))rotate(((x==ch[y][1])==(y==ch[z][1]))?y:x);
    		upd(x);
    	}
    	il vd access(int x){for(rg int y=0;x;x=fa[y=x])splay(x),ch[x][1]=y,upd(x);}
    	il vd makert(const int&x){access(x),splay(x);rev[x]^=1;}
    	il int find(int x){access(x),splay(x);while(ch[x][0])x=ch[x][0];return x;}
    	il vd split(const int&x,const int&y){makert(x);access(y),splay(y);}
    	il vd _link(const int&x,const int&y){makert(x),fa[x]=y;}
    	il vd cut(const int&x,const int&y){split(x,y);fa[x]=ch[y][0]=0;}
    	il vd link(const int&x,const int&y,const int&k){
    		if(find(x)^find(y)){w[++index]=k,_link(A[index]=x,index),_link(B[index]=y,index);return;}
    		split(x,y);
    		sta int s;s=mx[y];
    		if(w[s]<=k)return;
    		cut(s,A[s]),cut(s,B[s]);
    		w[s]=k,_link(A[s]=x,s),_link(B[s]=y,s);
    	}
    	il int query(int x,int y){
    		if(find(x)^find(y))return 1e18;
    		split(x,y);return w[mx[y]];
    	}
    }
    struct edge{int x,y,a,b;}E[maxm];
    bool operator <(const edge&a,const edge&b){return a.a<b.a;}
    mainint main(){
    	freopen("magicalforest.in","r",stdin);
    	freopen("magicalforest.out","w",stdout);
    	int n=gi(),m=gi();
    	for(rg int i=1;i<=m;++i)E[i].x=gi(),E[i].y=gi(),E[i].a=gi(),E[i].b=gi();
    	std::sort(E+1,E+m+1);
    	int ans=1e18;
    	LCT::index=n;
    	for(rg int i=1;i<=m;++i)LCT::link(E[i].x,E[i].y,E[i].b),ans=std::min(ans,E[i].a+LCT::query(1,n));
    	if(ans==1e18)ans=-1;printf("%lld
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    使用gradle打包时将依赖也合并入jar包
    fiddler win10-1703Failed to register Fiddler as the system proxy
    VC编译选项 多线程(/MT)
    [转载]ACM(访问控制模型),Security Identifiers(SID),Security Descriptors(安全描述符),ACL(访问控制列表),Access Tokens(访问令牌)
    线程操作函数
    注册表使用技巧
    在github上参与开源项目日常流程
    盘点富人和穷人九大经典差异
    C++程序风格的思考
    mfc窗口,父窗口parentwindow,所有者窗口ownerwindow 区别
  • 原文地址:https://www.cnblogs.com/xzz_233/p/cogs1685.html
Copyright © 2020-2023  润新知