NOI2014魔法森林

题目链接

把边按a从小到大排序,枚举一条边,相当于只考虑<=ai的边,根据b做一个最小生成树再算答案。

用lct维护这个最小生成树,要加入的这条边若会形成环,则找到x到y路径上最大的b,与当前边比较看加还是不加(加就把那条边删掉)。

维护边权可以把边看做一个点,点权为边权,并与原边的两个端点连边。

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<vector>
#include<algorithm>
#include<queue>
#include<cmath>
#include<stack>
#include<map>
#define P puts("lala")
#define cp cerr<<"lala"<<endl
#define ln putchar('
')
#define sp putchar(' ')
#define pb push_back
#define fi first
#define se second 
#define mkp make_pair
using namespace std;
typedef pair<int,int> pii;
inline void read(int &re)
{
    char ch=getchar();int g=1;
    while(ch<'0'||ch>'9') {if(ch=='-')g=-1;ch=getchar();}
    re=0;
    while(ch<='9'&&ch>='0') re=(re<<1)+(re<<3)+(ch^48),ch=getchar();
    re*=g;
}
typedef long long ll;
inline void read(ll &re)
{
    char ch=getchar();ll g=1;
    while(ch<'0'||ch>'9') {if(ch=='-')g=-1;ch=getchar();}
    re=0;
    while(ch<='9'&&ch>='0') re=(re<<1)+(re<<3)+ch-48ll,ch=getchar();
    re*=g;
}
const int N=150050;
struct node
{
    int x,y,a,b;
    node() {x=0;y=0;a=0;b=0;}
}e[N];
bool operator < (node a,node b)
{
    return a.a<b.a;
}
int n,m;
int maxv[N],maxwh[N],fa[N],ch[N][2],val[N];
bool rev[N];
inline bool ge(int x) {return ch[fa[x]][1]==x;}
inline bool isroot(int x) {return ch[fa[x]][1]!=x&&ch[fa[x]][0]!=x;}
inline void up(int x)
{
    if(!x) return ;
    maxv[x]=val[x]; maxwh[x]=x;
    if(ch[x][0]) 
    {
        if(maxv[ch[x][0]]>maxv[x]) maxwh[x]=maxwh[ch[x][0]],maxv[x]=maxv[ch[x][0]];
    }
    if(ch[x][1]) 
    {
        if(maxv[ch[x][1]]>maxv[x]) maxwh[x]=maxwh[ch[x][1]],maxv[x]=maxv[ch[x][1]];
    }
}
inline void pushdown(int x)
{
    if(x&&rev[x])
    {
        if(ch[x][0]) rev[ch[x][0]]^=1;
        if(ch[x][1]) rev[ch[x][1]]^=1;
        rev[x]=0;
        swap(ch[x][0],ch[x][1]);
    }
}
inline void rotate(int x)
{
    int f=fa[x],g=fa[f],wh=ge(x);
    if(!isroot(f)) ch[g][ch[g][1]==f]=x;
    ch[f][wh]=ch[x][wh^1]; fa[ch[f][wh]]=f;
    ch[x][wh^1]=f; fa[f]=x;
    fa[x]=g;
    up(f);up(x);
}
int st[N],top=0;
void splay(int x)
{
    top=0;st[++top]=x;
    for(int i=x;!isroot(i);i=fa[i]) st[++top]=fa[i];
    for(int i=top;i;--i) pushdown(st[i]);

    for(int f;(f=fa[x])&&!isroot(x);rotate(x))
        if(!isroot(f)) rotate(ge(x)==ge(f)?f:x);
}
void access(int x)
{
    for(int t=0;x;t=x,x=fa[x])
        splay(x),ch[x][1]=t,up(x);
}
void makeroot(int x)
{
    access(x); splay(x); rev[x]^=1;
}
int find(int x)
{
    access(x); splay(x);
    while(ch[x][0]) x=ch[x][0]; splay(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);
    fa[x]=0; ch[y][0]=0; up(y);
}
int query(int x,int y)
{
    makeroot(x); access(y); splay(y);
    return maxv[y];
}


const int inf=0x3f3f3f3f;
int main()
{
#ifndef ONLINE_JUDGE
    freopen("1.in","r",stdin);freopen("1.out","w",stdout);
#endif
    int i,j,opt,T;
    read(n);read(m);
    for(i=1;i<=m;++i)
    {
        read(e[i].x);read(e[i].y);read(e[i].a);read(e[i].b);
    }
    sort(e+1,e+1+m);
    int ans=inf;
    for(i=1;i<=n+m;++i) maxwh[i]=i;
    for(i=1;i<=m;++i)
    {
        int x=e[i].x,y=e[i].y;
        if(x==y) continue;
        val[i+n]=e[i].b; maxv[i+n]=e[i].b;
        if(find(x)!=find(y)) link(x,i+n),link(i+n,y);
        else
        {
            makeroot(x); access(y); splay(y);
            int k=maxwh[y]-n;
            if(e[k].b<e[i].b) continue;
            cut(e[k].x,k+n); cut(k+n,e[k].y);
            link(x,i+n); link(i+n,y);
        }
        if(find(1)==find(n)) ans=min(ans,e[i].a+query(1,n));
    }
    printf("%d",ans==inf?-1:ans);
    return 0;
}
/*

*/
原文地址:https://www.cnblogs.com/thkkk/p/7856266.html