[NOI 2014]魔法森林

题意:求带修最短路。

思路:一开始想的就是LCT维护一棵最小生成树,后来发现还有动态开点SPFA的这种操作...神了

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>

using namespace std;

const int N=300010;

int ch[N][2],pre[N],v[N],pos[N],fa[N];

bool rev[N];

int Q[N],n,m;

struct node
{
    int x,y,a,b;
}po[N];


int cmp(const node &A,const node &B) {
    if (A.a!=B.a) return A.a<B.a;
    else return A.b<B.b;
}

int get(int num) {
    return ch[pre[num]][0]==num? 0:1;
}

int isroot(int num) { 
    return ch[pre[num]][0]!=num&&ch[pre[num]][1]!=num;
}

void update(int num) {
    if (!num) return;
    pos[num]=num;
    int l=ch[num][0];
    int r=ch[num][1];
    if (l&&v[pos[l]]>v[pos[num]]) pos[num]=pos[l];
    if (r&&v[pos[r]]>v[pos[num]]) pos[num]=pos[r];
}

void push(int num) {
    if (!num) return;
    if (rev[num]) {
        if (ch[num][0]) rev[ch[num][0]]^=1;
        if (ch[num][1]) rev[ch[num][1]]^=1;
        swap(ch[num][0],ch[num][1]);
        rev[num]^=1;
    }
}

void rotate(int num) {
    int fa=pre[num];
    int grand=pre[fa];
    int wh=get(num);
    if (!isroot(fa)) ch[grand][ch[grand][0]==fa? 0:1]=num;
    pre[num]=grand;
    ch[fa][wh]=ch[num][wh^1];
    pre[ch[fa][wh]]=fa;
    ch[num][wh^1]=fa;
    pre[fa]=num;
    update(fa);
    update(num);
}

void splay(int num) {
    int top=0;
    Q[++top]=num;
    for (int i=num; !isroot(i); i=pre[i])
        Q[++top]=pre[i];
    while (top) push(Q[top--]);
    for (int fa; !isroot(num); rotate(num))
        if (!isroot(fa=pre[num]))
            rotate(get(num)==get(fa)? fa:num);
}

void expose(int num) {
    int t=0;
    while (num) {
        splay(num);
        ch[num][1]=t;
        update(num);
        t=num;
        num=pre[num];
    }
}

void makeroot(int num) {
    expose(num);
    splay(num);
    rev[num]^=1;
}

void link(int x,int y) {
    makeroot(x);
    pre[x]=y;
}

void cut(int x,int y) {
    makeroot(x);
    expose(y);
    splay(y);
    ch[y][0]=pre[x]=0;
}

int way(int x,int y) {
    makeroot(x);
    expose(y);
    splay(y);
    return pos[y];
}

int find(int x) {
    if (fa[x]!=x) fa[x]=find(fa[x]);
    return fa[x];
}

int main() {
    scanf("%d%d",&n,&m);
    for (int i=1; i<=m; i++)
        scanf("%d%d%d%d",&po[i].x,&po[i].y,&po[i].a,&po[i].b);

    int ans=1e9;
    sort(po+1,po+1+m,cmp);
    for (int i=1; i<=n; i++) fa[i]=i;
    for (int i=1; i<=m; i++) {
        int f1=find(po[i].x);
        int f2=find(po[i].y);
        if (f1!=f2) {
            fa[f1]=f2;
        } 
        else {
            int p=way(po[i].x,po[i].y);   
            if (v[p]>po[i].b) {
                cut(p,po[p-n].x);
                cut(p,po[p-n].y);
            } else {
                if (find(1)==find(n))
                    ans=min(ans,v[way(1,n)]+po[i].a);
                continue;
            }
        }
        v[i+n]=po[i].b;
        pos[i+n]=i+n;
        link(po[i].x,n+i);
        link(po[i].y,n+i);
        if (find(1)==find(n))
        {
            int p=way(1,n);
            ans=min(ans,v[p]+po[i].a);
        }
    }

    if (ans==1e9) 
      printf("-1");
    else 
      printf("%d",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/akoasm/p/9419370.html