bzoj3669: [Noi2014]魔法森林 LCT

来源:互联网 发布:淘宝网触屏版下载安装 编辑:程序博客网 时间:2024/05/03 16:49
题解:
暴力的想法是枚举a的上界,做b的最小生成树。
而且有一个比较显然的性质是:
如果可以在一个生成树中加入一条边,使得树的总权值更小,那么一定是(设这条边连接 x,y)x--y原路径上的最大权值<这条边的权值
删掉这条边,加上新边。
那么我们只需要用LCT,维护点与点之间的最大权值,将边以a排序,一条一条试图往里面加即可。
如果x,y不连通直接加入,否则按上述查询x,y的最大值,比较。
然后每次都更新一下答案。
需要注意的是,边权可以转化成点权,我们从x,y各向这个新点连边、删边即可。
#include <iostream>#include <algorithm>#include <cstdio>#include <cstring>#include <cmath>using namespace std;int INF=0x3f3f3f3f;#define maxn 160000int getint(){    char c;int res;    while(c=getchar(),c<'0'||c>'9');    res=c-'0';    while(c=getchar(),c>='0'&&c<='9')        res=res*10+c-'0';    return res;}struct node{int x,y,a,b;}e[maxn];int n,m,ans,fa[maxn],tr[maxn][2],f[maxn],next[maxn],mx[maxn],v[maxn];bool rev[maxn];bool isroot(int x){    return (tr[fa[x]][0]!=x)&&(tr[fa[x]][1]!=x);}inline void pushup(int x){    mx[x]=x;    if(v[mx[tr[x][0]]]>v[mx[x]])        mx[x]=mx[tr[x][0]];    if(v[mx[tr[x][1]]]>v[mx[x]])        mx[x]=mx[tr[x][1]];}void rotate(int x){    int l,r,y,z;    y=fa[x];z=fa[y];    if(tr[y][0]==x) l=0;    else l=1;r=l^1;    if(!isroot(y))    {        if(tr[z][0]==y) tr[z][0]=x;        else tr[z][1]=x;    }    fa[x]=z;fa[y]=x;fa[tr[x][r]]=y;    tr[y][l]=tr[x][r];tr[x][r]=y;    pushup(y);pushup(x);}void pushdown(int x){    if(!isroot(x))        pushdown(fa[x]);    if(rev[x])    {        rev[x]^=1;rev[tr[x][1]]^=1;rev[tr[x][0]]^=1;        swap(tr[x][0],tr[x][1]);    }}void splay(int x){    pushdown(x);    int y,z;    while(!isroot(x))    {        y=fa[x];z=fa[y];        if(!isroot(y))        {            if((tr[y][0]==x)^(tr[z][0]==y)) rotate(x);            else rotate(y);        }        rotate(x);    }}void access(int x){    int t=0;    while(x)    {        splay(x);        tr[x][1]=t;        pushup(x);        t=x;x=fa[x];    }}void makeroot(int x){    access(x);splay(x);rev[x]^=1;}void link(int x,int y){    makeroot(x);fa[x]=y;splay(x);}void cut(int x,int y){    makeroot(x);access(y);splay(y);    fa[x]=0;tr[y][0]=0;}int getf(int x){    return f[x]==x?x:f[x]=getf(f[x]);}inline int ask(int x,int y){    makeroot(x);access(y);splay(y);return mx[y];}bool cmp(node aa,node bb){    return aa.a<bb.a;}int main(){    n=getint();m=getint();    for(int i=1;i<=n;i++) f[i]=i;    for(int i=1;i<=m;i++)    {        e[i].x=getint();e[i].y=getint();        e[i].a=getint();e[i].b=getint();    }    int r1,r2,x,y,tmp;ans=INF;    sort(e+1,e+1+m,cmp);    for(int i=1;i<=m;i++)    {        mx[i]=i+n;        v[i+n]=e[i].b;    }    for(int i=1;i<=m;i++)    {        x=e[i].x;y=e[i].y;        r1=getf(x);r2=getf(y);        if(r1!=r2)        {            f[r1]=r2;            link(x,n+i);link(y,n+i);        }        else        {            tmp=ask(x,y);            if(e[i].b<v[tmp])            {                cut(e[tmp-n].x,tmp);cut(e[tmp-n].y,tmp);                link(x,n+i);link(y,n+i);            }        }        if(getf(1)==getf(n))ans=min(ans,v[ask(1,n)]+e[i].a);    }    printf("%d\n",ans==INF?-1:ans);    return 0;}

0 0