【bzoj3669】[Noi2014]魔法森林 LCT

Description

为了得到书法大家的真传,小E同学下定决心去拜访住在魔法森林中的隐士。魔法森林可以被看成一个包含个N节点M条边的无向图,节点标号为1..N,边标号为1..M。初始时小E同学在号节点1,隐士则住在号节点N。小E需要通过这一片魔法森林,才能够拜访到隐士。
魔法森林中居住了一些妖怪。每当有人经过一条边的时候,这条边上的妖怪就会对其发起攻击。幸运的是,在号节点住着两种守护精灵:A型守护精灵与B型守护精灵。小E可以借助它们的力量,达到自己的目的。
只要小E带上足够多的守护精灵,妖怪们就不会发起攻击了。具体来说,无向图中的每一条边Ei包含两个权值Ai与Bi。若身上携带的A型守护精灵个数不少于Ai,且B型守护精灵个数不少于Bi,这条边上的妖怪就不会对通过这条边的人发起攻击。当且仅当通过这片魔法森林的过程中没有任意一条边的妖怪向小E发起攻击,他才能成功找到隐士。
由于携带守护精灵是一件非常麻烦的事,小E想要知道,要能够成功拜访到隐士,最少需要携带守护精灵的总个数。守护精灵的总个数为A型守护精灵的个数与B型守护精灵的个数之和。
Input

第1行包含两个整数N,M,表示无向图共有N个节点,M条边。 接下来M行,第行包含4个正整数Xi,Yi,Ai,Bi,描述第i条无向边。其中Xi与Yi为该边两个端点的标号,Ai与Bi的含义如题所述。 注意数据中可能包含重边与自环。

Output

输出一行一个整数:如果小E可以成功拜访到隐士,输出小E最少需要携带的守护精灵的总个数;如果无论如何小E都无法拜访到隐士,输出“-1”(不含引号)。

Sample Input

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

Sample Output

【输出样例1】

32

【样例说明1】

如果小E走路径1→2→4,需要携带19+15=34个守护精灵;

如果小E走路径1→3→4,需要携带17+17=34个守护精灵;

如果小E走路径1→2→3→4,需要携带19+17=36个守护精灵;

如果小E走路径1→3→2→4,需要携带17+15=32个守护精灵。

综上所述,小E最少需要携带32个守护精灵。

【输出样例2】

-1

【样例说明2】

小E无法从1号节点到达3号节点,故输出-1。

HINT

2<=n<=50,000

0<=m<=100,000

1<=ai ,bi<=50,000

Source

按权值a排序然后加边,LCT维护权值b,更新答案用当前的a+当前路径上最大的b更新答案…若成环,当前的边的b比最大的b要小,则删掉最大权值的那个边然后连上这个边…

我是来复习模板的…好吧重新抄了一遍

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;

typedef long long LL;
const int SZ = 1000010;
const int INF = 1000000010;
const double eps = 1e-6;

struct node{
    node *ch[2],*f;
    int v;
    node *mx;
    bool rev;

    int dir() { return f -> ch[1] == this; }

    bool isroot() { return f -> ch[0] != this && f -> ch[1] != this; }

    void maintain()
    {
        mx = this;
        if(ch[0] -> mx -> v > mx -> v) mx = ch[0] -> mx;
        if(ch[1] -> mx -> v > mx -> v) mx = ch[1] -> mx;
    }

    void pushdown();

    void setc(node *x,int d) { (ch[d] = x) -> f = this; }
}T[SZ], *null, *rt[SZ];

int Tcnt = 0;

node* newnode(int x)
{
    node *k = T + (Tcnt ++);
    k -> ch[0] = k -> ch[1] = k -> f = null;
    k -> rev = 0;
    k -> v = x;
    k -> mx = k;
    return k;
}

void pushrev(node *p)
{
    if(p == null) return ;
    p -> rev ^= 1;
    swap(p -> ch[0],p -> ch[1]);
}

void node :: pushdown()
{
    if(rev) { pushrev(ch[0]); pushrev(ch[1]); rev = 0; }
}


void rotate(node *p)
{
    int d = p -> dir();
    node *fa = p -> f;
    p -> f = fa -> f;
    if(!fa -> isroot())
        p -> f -> ch[fa -> dir()] = p;
    fa -> ch[d] = p -> ch[d ^ 1];
    if(fa -> ch[d] != null)
        fa -> ch[d] -> f = fa;
    p -> setc(fa,d ^ 1);
    fa -> maintain(); p -> maintain();
}

node *S[SZ];

void pushpath(node *p)
{
    int top = 0;
    while(!p -> isroot()) S[++ top] = p,p = p -> f;
    S[++ top] = p;
    while(top) S[top --] -> pushdown(); 
}

void splay(node *p)
{
    pushpath(p);
    while(!p -> isroot())
    {
        if(p -> f -> isroot()) rotate(p);
        else
        {
            if(p -> dir() == p -> f -> dir())
                rotate(p -> f),rotate(p);
            else
                rotate(p),rotate(p);
        }
    }
    p -> maintain();
}

void access(node *p)
{
    node *last = null;
    while(p != null)
    {
        splay(p);
        p -> ch[1] = last; p -> maintain();
        last = p;
        p = p -> f;
    }
}

void toroot(node *p)
{
    access(p); splay(p); pushrev(p);
}

void link(node *u,node *v)
{
    toroot(u);
    u -> f = v;
}

void cut(node *u,node *v)
{
    toroot(u); access(v); splay(v);
    v -> ch[0] = u -> f = null; v -> maintain();
}

node* find_max(node *u,node *v)
{
    toroot(u); access(v); splay(v);
    return v -> mx;
}

bool issame(node *u,node *v)
{
    while(u -> f != null) u = u -> f;
    while(v -> f != null) v = v -> f;
    return u == v;
}

int n,m;

void init()
{
    null = newnode(0);
    for(int i = 1;i <= n;i ++)
        rt[i] = newnode(0);
}

struct edge{
    int f,t,a,b;
}l[SZ];

bool cmp(edge a,edge b) { return a.a < b.a; }

int main()
{
//  freopen("ex_forest3.in","r",stdin);
    scanf("%d%d",&n,&m);
    init();
    for(int i = 1;i <= m;i ++)
        scanf("%d%d%d%d",&l[i].f,&l[i].t,&l[i].a,&l[i].b);
    sort(l + 1,l + 1 + m,cmp);

    for(int i = 1;i <= m;i ++)
        rt[i + n] = newnode(l[i].b);
    int ans = INF;
    bool flag = 0;

    for(int i = 1;i <= m;i ++)
    {
        if(issame(rt[l[i].f],rt[l[i].t]))
        {
            node *k = find_max(rt[l[i].f],rt[l[i].t]);
            if(k -> v > l[i].b)
                cut(k,rt[l[k - T - n].f]),cut(k,rt[l[k - T - n].t]);
            else
                continue;
        }

        link(rt[l[i].f],rt[i + n]);
        link(rt[l[i].t],rt[i + n]);

        if(flag || issame(rt[1],rt[n]))
            ans = min(ans,l[i].a + find_max(rt[1],rt[n]) -> v),flag = 1; } printf("%d",ans == INF ? -1 : ans); return 0; } 

你可能感兴趣的:(【bzoj3669】[Noi2014]魔法森林 LCT)