您的位置:首页 > 运维架构

NOI2014 魔法森林 LCT维护MST

2017-12-02 10:21 281 查看
BZOJ3669 题面

从更简单的情况入手,如果边权只有a没有b应该怎么处理?这时候问题就是找一条从1到N的路径,使得最长的边尽量短。根据最小生成树的性质,这样的边一定在最小生成树上。

如果a固定,得到的解法是一样的。那么可以分别讨论每一个a,对于权值不大于a的边对b做一次最小生成树。暴力做会超时。考虑到随着a的变大,可用的边也逐渐增多,那么只要在加边的同时更新最小生成树就可以了。这个操作可以用LCT处理。

#include<stdio.h>
#include<algorithm>
#define MAXN 150005
#define MAXM 200005
using namespace std;

int N,M,Ans=1e9;

struct node{int st,en,va,vb;}edge[MAXM];
bool operator<(node x,node y)
{
if(x.va==y.va)return x.vb<y.vb;
return x.va<y.va;
}

int ls[MAXN],rs[MAXN],fa[MAXN],rev[MAXN],val[MAXN];
int Max[MAXN],id[MAXN];

bool isrt(int x){return ls[fa[x]]!=x&&rs[fa[x]]!=x;}

void Update(int p)
{
if(Max[ls[p]]>Max[rs[p]])Max[p]=Max[ls[p]],id[p]=id[ls[p]];
else Max[p]=Max[rs[p]],id[p]=id[rs[p]];
if(Max[p]<val[p])Max[p]=val[p],id[p]=p;
}

void Putdown(int p)
{
if(rev[p]==0)return;
rev[ls[p]]^=1;rev[rs[p]]^=1;rev[p]=0;
swap(ls[p],rs[p]);
}

void Zig(int x)
{
int y=fa[x],z=fa[y];
if(!isrt(y))
{
if(ls[z]==y)ls[z]=x;
else rs[z]=x;
}
fa[x]=z;fa[y]=x;fa[rs[x]]=y;
ls[y]=rs[x];rs[x]=y;
Update(y);Update(x);
}

void Zag(int x)
{
int y=fa[x],z=fa[y];
if(!isrt(y))
{
if(ls[z]==y)ls[z]=x;
else rs[z]=x;
}
fa[x]=z;fa[y]=x;fa[ls[x]]=y;
rs[y]=ls[x];ls[x]=y;
Update(y);Update(x);
}

int s[MAXN],Top;
void Splay(int x)
{
int i,y,z;

s[++Top]=x;
for(i=x;!isrt(i);i=fa[i])s[++Top]=fa[i];
while(Top)Putdown(s[Top--]);

while(!isrt(x))
{
y=fa[x];z=fa[y];
if(isrt(y))
{
if(ls[y]==x)Zig(x);

e850
else Zag(x);
}
else
{
if(ls[z]==y)
{
if(ls[y]==x)Zig(y),Zig(x);
else Zag(x),Zig(x);
}
else
{
if(rs[y]==x)Zag(y),Zag(x);
else Zig(x),Zag(x);
}
}
}
}

void Access(int x)
{
int t=0;
while(x)
{
Splay(x);
rs[x]=t;Update(x);
t=x;x=fa[x];
}
}

void SetRt(int x)
{
Access(x);Splay(x);rev[x]^=1;
}

void Link(int x,int y)
{
SetRt(x);fa[x]=y;
}

void Cut(int x,int y)
{
SetRt(x);
Access(y);Splay(y);
ls[y]=fa[x]=0;
Update(y);
}

int FindRt(int x)
{
Access(x);Splay(x);
while(ls[x])x=ls[x];
return x;
}

int tot,lk[MAXM][2];
void Add(int x,int y,int v)
{
tot++;
lk[tot][0]=x;lk[tot][1]=y;
val[tot]=v;id[tot]=tot;
Link(x,tot);Link(tot,y);
}

void Del(int x)
{
Cut(x,lk[x][0]);Cut(x,lk[x][1]);
}

int GetMax(int x,int y,int op)
{
SetRt(x);
Access(y);Splay(y);
if(op==1)return Max[y];
else return id[y];
}

int main()
{
int i,j;

scanf("%d%d",&N,&M);
for(i=1;i<=M;i++)scanf("%d%d%d%d",&edge[i].st,&edge[i].en,&edge[i].va,&edge[i].vb);

sort(edge+1,edge+M+1);

tot=N;
for(i=j=1;i<=50000;i++)
{
while(j<=M&&edge[j].va<=i)
{
int x,y;

if(edge[j].st==edge[j].en){j++;continue;}

x=FindRt(edge[j].st);
y=FindRt(edge[j].en);
if(x!=y)Add(edge[j].st,edge[j].en,edge[j].vb);
else
{
int tmp=GetMax(edge[j].st,edge[j].en,1);
if(tmp>edge[j].vb)
{
tmp=GetMax(edge[j].st,edge[j].en,2);
Del(tmp);Add(edge[j].st,edge[j].en,edge[j].vb);
}
}
j++;
}
if(FindRt(1)!=FindRt(N))continue;
Ans=min(Ans,i+GetMax(1,N,1));
}

if(Ans==1e9)puts("-1");
else printf("%d\n",Ans);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: