bzoj 3669: [Noi2014]魔法森林

来源:互联网 发布:手机拨号软件 编辑:程序博客网 时间:2024/05/18 03:03

题意:

在无向图中找一条1到n的路径,使其中max{a}+max{b}最小。

题解:

lct+类似最小生成树。
首先假如这只有一个参数,那么就是水题了。
但是有两个参数,考虑按a值排序,每次将a值相同的边加进去,然后计算答案。
那么怎么知道此时1到n的最小的最大b值呢?
用lct维护一个类似最小生成树的东西,对于一条边,都看作一个点,边权做点权,向他原来连接的点连边。
当加入时,先看看是否成环,不成环直接加上就好了。
当成环的时候,那么就找到这条链上的最大权的点(lct维护),假如大于当前加的点,那就cut掉,link新点,否则保留原来的。
然后没有然后了。
code:

#include<cstdio>#include<cstdlib>#include<cstring>#include<iostream>#include<algorithm>using namespace std;struct trnode{    int fa,son[2],rev,d,c;}tr[150010];int mymax(int x,int y){return tr[x].d>tr[y].d?x:y;}void update(int x){    int lc=tr[x].son[0],rc=tr[x].son[1];    tr[x].c=mymax(tr[lc].c,tr[rc].c);    tr[x].c=mymax(tr[x].c,x);    if(tr[x].rev)    {        tr[x].rev=0;tr[lc].rev^=1;tr[rc].rev^=1;        swap(tr[x].son[0],tr[x].son[1]);    }}bool is_root(int x){    int fa=tr[x].fa;    if(tr[fa].son[0]==x||tr[fa].son[1]==x) return false;    return true;}void pushdown(int x){    if(!is_root(x)) pushdown(tr[x].fa);    update(x);}void rotate(int x){    int y=tr[x].fa,z=tr[y].fa,w,R,r;    w=(tr[y].son[0]==x);    R=y;r=tr[x].son[w];    tr[R].son[1-w]=r;    if(r) tr[r].fa=R;    R=z;r=x;    if(!is_root(y)) tr[R].son[tr[z].son[1]==y]=r;    if(r) tr[r].fa=R;    R=x;r=y;    tr[R].son[w]=r;    if(r) tr[r].fa=R;    update(y);update(x);}void splay(int x){    pushdown(x);    while(!is_root(x))    {        int y=tr[x].fa,z=tr[y].fa;        if(is_root(y)) rotate(x);        else            if((tr[z].son[0]==y)==(tr[y].son[0]==x)) rotate(y),rotate(x);            else rotate(x),rotate(x);    }}void access(int x){    int last=0;    while(x)    {        splay(x);        tr[x].son[1]=last;        update(x);        last=x;x=tr[x].fa;    }}void make_root(int x){    access(x);    splay(x);    tr[x].rev^=1;}void split(int x,int y){    make_root(x);    access(y);    splay(y);}void link(int x,int y){    make_root(x);    tr[x].fa=y;}void cut(int x,int y){    split(x,y);    tr[x].fa=tr[y].son[0]=0;    update(y);}int find_root(int x){    access(x);    splay(x);    while(tr[x].son[0]) x=tr[x].son[0];    return x;}int n,m;struct node{    int x,y,a,b;}a[100010];int ans=-1;bool cmp(node a,node b){return a.a<b.a;}void cc(int &x,int y){if(x==-1) x=y;x=min(x,y);}void add(node b,int num){    int x=b.x,y=b.y,tx=find_root(x),ty=find_root(y);    tr[num].d=b.b;    if(tx!=ty) link(x,num),link(y,num);    else    {        split(x,y);        int c=tr[y].c;        if(tr[c].d<=b.b) return;        cut(c,a[c-n].x);cut(c,a[c-n].y);        link(x,num);link(y,num);    }}void solve(int a){    int tx=find_root(1),ty=find_root(n);    if(tx==ty) split(1,n),cc(ans,a+tr[tr[n].c].d);}int read(){    int x=0,f=1;char ch=getchar();    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}    return x*f;}int main(){    n=read();m=read();    for(int i=1;i<=m;i++) a[i].x=read(),a[i].y=read(),a[i].a=read(),a[i].b=read();    sort(a+1,a+m+1,cmp);    for(int i=1;i<=m;i++)    {        add(a[i],i+n);        if(i==m||a[i+1].a!=a[i].a) solve(a[i].a);    }    printf("%d",ans);}
原创粉丝点击