您的位置:首页 > 其它

NKOJ 2991 (NOI 2014) 魔法森林 (动态树+最小生成树)

2017-12-01 20:24 357 查看

P2991【NOI2014 Day1】魔法森林

问题描述



输入格式



输出格式



样例输入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

样例输出1

32

样例输出2

-1

数据范围



注意到这道题每条边有两个权值,所求为经过路径上每种权值的最大值之和的最小值。

考虑只有一种权值,那么显然最小生成树。

考虑有两种权值,那么将边按一种权值排序,从小到大讨论,维护另一种权值的最小生成树,而当前的答案 就是当前边的第一种权值,加上另一种权值的最小生成树上从1到N的最大权值。

正确性是显然的,讨论完所有边取所有答案的最小值即可。

代码:

#include<stdio.h>
#include<iostream>
#include<algorithm>
4000

#include<cstring>
#define N 500005
using namespace std;
struct node{int x,y,a,b,id;}edge
;
int n,m,S
,top,Hash
,F
,ans;
int ls
,rs
,fa
,v
,Max
,id
,rev
;
int GF(int x)
{
if(F[x]!=x)F[x]=GF(F[x]);
return F[x];
}
bool cmp(node aa,node bb)
{return aa.a<bb.a;}
int GM(int x,int y,int z)
{
if(x>=y&&x>=z)return x;
if(y>=z)return y;
return z;
}
bool Isroot(int x)
{return ls[fa[x]]!=x&&rs[fa[x]]!=x;}
void MT(int x)
{
Max[x]=GM(v[x],Max[ls[x]],Max[rs[x]]);
if(Max[x]==v[x])id[x]=x;
else if(Max[x]==Max[ls[x]])id[x]=id[ls[x]];
else id[x]=id[rs[x]];
}
void PD(int x)
{
if(rev[x])
{
swap(ls[x],rs[x]);
rev[ls[x]]^=1;
rev[rs[x]]^=1;
rev[x]^=1;
}
}
void Zig(int x)
{
int y=fa[x],z=fa[y];
if(!Isroot(y))y==ls[z]?ls[z]=x:rs[z]=x;fa[x]=z;
ls[y]=rs[x];fa[rs[x]]=y;
rs[x]=y;fa[y]=x;
MT(y);MT(x);
}
void Zag(int x)
{
int y=fa[x],z=fa[y];
if(!Isroot(y))y==ls[z]?ls[z]=x:rs[z]=x;fa[x]=z;
rs[y]=ls[x];fa[ls[x]]=y;
ls[x]=y;fa[y]=x;
MT(y);MT(x);
}
void Splay(int x)
{
int i,y,z;
S[++top]=x;
for(i=x;!Isroot(i);i=fa[i])S[++top]=fa[i];
while(top)PD(S[top--]);
while(!Isroot(x))
{
y=fa[x];z=fa[y];
if(!Isroot(y))
{
if(y==ls[z])x==ls[y]?(Zig(y),Zig(x)):(Zag(x),Zig(x));
else x==rs[y]?(Zag(y),Zag(x)):(Zig(x),Zag(x));
}
else x==ls[y]?Zig(x):Zag(x);
}
}
void Access(int x)
{
for(int t=0;x;x=fa[x])
{
Splay(x);
rs[x]=t;
MT(x);t=x;
}
}
void Makeroot(int x)
{
Access(x);
Splay(x);
rev[x]^=1;
}
int Findroot(int x)
{
Access(x);
Splay(x);
while(ls[x])x=ls[x];
return x;
}
void Link(int x,int y)
{
Makeroot(x);
fa[x]=y;
}
void Cut(int x,int y)
{
Makeroot(x);
Access(y);
Splay(y);
ls[y]=fa[x]=0;
}
bool Kruscal()
{
int i,j,k,x,y,cnt;bool f=0;
for(i=1;i<=n;i++)F[i]=i;
i=1;cnt=0;ans=1e9;
while(i<=m)
{
x=GF(edge[i].x);
y=GF(edge[i].y);
if(x!=y)
{
F[x]=y;cnt++;
Link(edge[i].x,edge[i].id);
Link(edge[i].y,edge[i].id);
}
else
{
Makeroot(edge[i].x);
Access(edge[i].y);
Splay(edge[i].y);
if(Max[edge[i].y]>edge[i].b)
{
k=Hash[id[edge[i].y]];
Cut(edge[k].x,edge[k].id);
Cut(edge[k].y,edge[k].id);
Link(edge[i].x,edge[i].id);
Link(edge[i].y,edge[i].id);
}
}
if(f||Findroot(1)==Findroot(n))
{
Makeroot(1);
Access(n);
Splay(n);
ans=min(ans,edge[i].a+Max
);
f=1;
}
i++;
}
if(f)return 1;
return 0;
}
int main()
{
int i,x,y;
scanf("%d%d",&n,&m);
for(i=1;i<=m;i++)scanf("%d%d%d%d",&edge[i].x,&edge[i].y,&edge[i].a,&edge[i].b),edge[i].id=n+i;
sort(edge+1,edge+m+1,cmp);
for(i=1;i<=m;i++)Hash[edge[i].id]=i,v[edge[i].id]=edge[i].b;
if(Kruscal())printf("%d",ans);
else printf("-1");
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: