• 【刷题】BZOJ 3669 [Noi2014]魔法森林


    Description

    为了得到书法大家的真传,小E同学下定决心去拜访住在魔法森林中的隐士。魔法森林可以被看成一个包含个N节点M条边的无向图,节点标号为1..N,边标号为1..M。初始时小E同学在号节点1,隐士则住在号节点N。小E需要通过这一片魔法森林,才能够拜访到隐士。

    魔法森林中居住了一些妖怪。每当有人经过一条边的时候,这条边上的妖怪就会对其发起攻击。幸运的是,在号节点住着两种守护精灵:A型守护精灵与B型守护精灵。小E可以借助它们的力量,达到自己的目的。

    只要小E带上足够多的守护精灵,妖怪们就不会发起攻击了。具体来说,无向图中的每一条边Ei包含两个权值Ai与Bi。若身上携带的A型守护精灵个数不少于Ai,且B型守护精灵个数不少于Bi,这条边上的妖怪就不会对通过这条边的人发起攻击。当且仅当通过这片魔法森林的过程中没有任意一条边的妖怪向小E发起攻击,他才能成功找到隐士。

    由于携带守护精灵是一件非常麻烦的事,小E想要知道,要能够成功拜访到隐士,最少需要携带守护精灵的总个数。守护精灵的总个数为A型守护精灵的个数与B型守护精灵的个数之和。

    Input

    第1行包含两个整数N,M,表示无向图共有N个节点,M条边。 接下来M行,第行包含4个正整数Xi,Yi,Ai,Bi,描述第i条无向边。其中Xi与Yi为该边两个端点的标号,Ai与Bi的含义如题所述。 注意数据中可能包含重边与自环。

    Output

    输出一行一个整数:如果小E可以成功拜访到隐士,输出小E最少需要携带的守护精灵的总个数;如果无论如何小E都无法拜访到隐士,输出“-1”(不含引号)。

    Sample Input

    【输入样例1】

    4 5  
    1 2 19 1  
    2 3 8 12  
    2 4 12 15  
    1 3 17 8  
    3 4 1 17  
    

    【输入样例2】

    3 1
    1 2 1 1
    

    Sample Output

    【输出样例1】

    32
    

    【样例说明1】

    如果小E走路径1→2→4,需要携带19+15=34个守护精灵;

    如果小E走路径1→3→4,需要携带17+17=34个守护精灵;

    如果小E走路径1→2→3→4,需要携带19+17=36个守护精灵;

    如果小E走路径1→3→2→4,需要携带17+15=32个守护精灵。

    综上所述,小E最少需要携带32个守护精灵。

    【输出样例2】

    -1
    

    【样例说明2】

    小E无法从1号节点到达3号节点,故输出-1。

    HINT

    2<=n<=50,000

    0<=m<=100,000

    1<=ai ,bi<=50,000

    Solution

    LCT

    看这道题,就是维护MST嘛

    但是有两个量怎么办?

    离线,把边按照 (a) 的权值排序,枚举 (a) 的值,把边权小于等于当前枚举的值的边加入LCT,而LCT维护 (b) 的MST

    这样就做完了(考虑了每一个 (a) 的情况下的最优解,取个 (min) 就是答案)

    #include<bits/stdc++.h>
    #define ll long long
    #define db double
    #define ld long double
    const int MAXN=50000+10,MAXM=100000+10,inf=0x3f3f3f3f;
    int n,m,ans=inf,limita,fa[MAXN];
    struct edge{
    	int u,v,a,b;
    	inline bool operator < (const edge &A) const {
    		return a<A.a;
    	};
    };
    edge side[MAXM];
    #define lc(x) ch[(x)][0]
    #define rc(x) ch[(x)][1]
    struct LCT{
    	int ch[MAXN+MAXM][2],fa[MAXN+MAXM],rev[MAXN+MAXM],Mx[MAXN+MAXM],id[MAXN+MAXM],val[MAXN+MAXM],stack[MAXN+MAXM],cnt;
    	inline void init()
    	{
    		memset(Mx,0,sizeof(Mx));
    		memset(id,0,sizeof(id));
    		memset(ch,0,sizeof(ch));
    		memset(fa,0,sizeof(fa));
    		memset(rev,0,sizeof(rev));
    	}
    	inline bool nroot(int x)
    	{
    		return lc(fa[x])==x||rc(fa[x])==x;
    	}
    	inline void reverse(int x)
    	{
    		std::swap(lc(x),rc(x));
    		rev[x]^=1;
    	}
    	inline void pushup(int x)
    	{
    		Mx[x]=val[x],id[x]=x;
    		if(Mx[lc(x)]>Mx[x])Mx[x]=Mx[lc(x)],id[x]=id[lc(x)];
    		if(Mx[rc(x)]>Mx[x])Mx[x]=Mx[rc(x)],id[x]=id[rc(x)];
    	}
    	inline void pushdown(int x)
    	{
    		if(rev[x])
    		{
    			if(lc(x))reverse(lc(x));
    			if(rc(x))reverse(rc(x));
    			rev[x]=0;
    		}
    	}
    	inline void rotate(int x)
    	{
    		int f=fa[x],p=fa[f],c=(rc(f)==x);
    		if(nroot(f))ch[p][rc(p)==f]=x;
    		fa[ch[f][c]=ch[x][c^1]]=f;
    		fa[ch[x][c^1]=f]=x;
    		fa[x]=p;
    		pushup(f);
    		pushup(x);
    	}
    	inline void splay(int x)
    	{
    		cnt=0;
    		stack[++cnt]=x;
    		for(register int i=x;nroot(i);i=fa[i])stack[++cnt]=fa[i];
    		while(cnt)pushdown(stack[cnt--]);
    		for(register int y=fa[x];nroot(x);rotate(x),y=fa[x])
    			if(nroot(y))rotate((lc(y)==x)==(lc(fa[y])==y)?y:x);
    		pushup(x);
    	}
    	inline void access(int x)
    	{
    		for(register int y=0;x;x=fa[y=x])splay(x),rc(x)=y,pushup(x);
    	}
    	inline int findroot(int x)
    	{
    		access(x);splay(x);
    		while(lc(x))pushdown(x),x=lc(x);
    		splay(x);
    		return x;
    	}
    	inline void makeroot(int x)
    	{
    		access(x);splay(x);reverse(x);
    	}
    	inline void split(int x,int y)
    	{
    		makeroot(x);access(y);splay(y);
    	}
    	inline void link(int x,int y)
    	{
    		makeroot(x);
    		if(findroot(y)!=x)fa[x]=y;
    	}
    	inline void cut(int x,int y)
    	{
    		makeroot(x);
    		if(findroot(y)==x&&fa[y]==x&&!lc(y))lc(x)=fa[y]=0,pushup(x);
    	}
    };
    LCT T;
    #undef lc
    #undef rc
    template<typename T> inline void read(T &x)
    {
    	T data=0,w=1;
    	char ch=0;
    	while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    	if(ch=='-')w=-1,ch=getchar();
    	while(ch>='0'&&ch<='9')data=((T)data<<3)+((T)data<<1)+(ch^'0'),ch=getchar();
    	x=data*w;
    }
    template<typename T> inline void write(T x,char c='')
    {
    	if(x<0)putchar('-'),x=-x;
    	if(x>9)write(x/10);
    	putchar(x%10+'0');
    	if(c!='')putchar(c);
    }
    template<typename T> inline void chkmin(T &x,T y){x=(y<x?y:x);}
    template<typename T> inline void chkmax(T &x,T y){x=(y>x?y:x);}
    template<typename T> inline T min(T x,T y){return x<y?x:y;}
    template<typename T> inline T max(T x,T y){return x>y?x:y;}
    inline int found(int x)
    {
    	if(fa[x]!=x)fa[x]=found(fa[x]);
    	return fa[x];
    }
    int main()
    {
    	read(n);read(m);
    	for(register int i=1;i<=n;++i)fa[i]=i;
    	T.init();
    	for(register int i=1;i<=m;++i)
    	{
    		read(side[i].u),read(side[i].v),read(side[i].a),read(side[i].b);
    		chkmax(limita,side[i].a);
    	}
    	std::sort(side+1,side+m+1);
    	for(register int a=1,sp=1;a<=limita;++a)
    	{
    		while(sp<=m&&side[sp].a<=a)
    		{
    			int x=found(side[sp].u),y=found(side[sp].v);
    			if(x!=y)
    			{
    				fa[x]=y;
    				T.val[sp+n]=side[sp].b;
    				T.link(sp+n,side[sp].u),T.link(sp+n,side[sp].v);
    			}
    			else
    			{
    				T.split(side[sp].u,side[sp].v);
    				int so=T.id[side[sp].v],sn=n+sp;
    				if(side[sp].b<T.Mx[side[sp].v])
    				{
    					T.val[sn]=side[sp].b;
    					T.cut(so,side[so-n].u);T.cut(so,side[so-n].v);
    					T.link(sn,side[sp].u);T.link(sn,side[sp].v);
    				}
    			}
    			++sp;
    		}
    		if(found(1)==found(n))T.split(1,n),chkmin(ans,a+T.Mx[n]);
    	}
    	if(ans==inf)write(-1,'
    ');
    	else write(ans,'
    ');
    	return 0;
    }
    
  • 相关阅读:
    解析SRT格式的电影字幕文件
    svn笔记
    一个REST风格的URI设计方案[Blog Web Services]
    微服务部署
    sleuth链路追踪
    springboot生成pdf
    绘制多个word表格,压缩文件夹并输出流
    数据库调优
    常用网站
    解决:pip Fatal error in launcher: Unable to create process using
  • 原文地址:https://www.cnblogs.com/hongyj/p/8709664.html
Copyright © 2020-2023  润新知