【NOI2014】魔法森林

题面

https://www.luogu.org/problem/P2387

题解

双关键字讨论处理,直接固定一个关键字枚举第二个即可。

$LCT$维护边上信息,拆边。

#include<cstdio>
#include<iostream>
#include<algorithm>
#define ri register int
#define N 50500
#define M 100500

int n,m;
int stk[N+M];
int top,ans;

using namespace std;

struct cut{
  int u,v,a,b;
  bool operator < (const cut& rhs) const {
    return a<rhs.a;
  }
} e[M];

struct binchaji{
  int f[N];
  void clear() {
    for (ri i=1;i<=n;i++) f[i]=i;
  }
  int findroot(int x) {
    if (f[x]==x) return x;
    return f[x]=findroot(f[x]);
  }
  void merge(int u,int v) {
    f[u]=v;
  }
} set;

struct link_cut_tree{
  int b[N+M],poi[N+M];
  int f[N+M],ch[N+M][2];
  bool rev[N+M];
  bool opt(int x) {
    return ch[f[x]][1]==x;
  }
  bool notroot(int x) {
    return ch[f[x]][0]==x || ch[f[x]][1]==x;
  }
  void update(int x) {
    poi[x]=x;
    if (ch[x][0] && b[poi[ch[x][0]]]>b[poi[x]]) poi[x]=poi[ch[x][0]];
    if (ch[x][1] && b[poi[ch[x][1]]]>b[poi[x]]) poi[x]=poi[ch[x][1]];
  }
  void rotate(int x) {
    int y=f[x],z=f[y],s=opt(x),w=ch[x][1^s];
    f[x]=z; if (notroot(y)) ch[z][opt(y)]=x;
    ch[y][s]=w; if (w) f[w]=y;
    f[y]=x; ch[x][1^s]=y;
    update(y); update(x);
  }
  void pushr(int x) {
    if (!rev[x]) return;
    rev[x]=0;
    swap(ch[x][0],ch[x][1]);
    if (ch[x][0]) rev[ch[x][0]]^=1;
    if (ch[x][1]) rev[ch[x][1]]^=1;
  }
  void splay(int x) {
    int y=x;
    top=0;
    while (notroot(y)) stk[++top]=y,y=f[y]; stk[++top]=y;
    while (top) pushr(stk[top]),top--;
    while (notroot(x)) {
      if (!notroot(f[x])) rotate(x);
      else {
        if (opt(x)==opt(f[x])) rotate(f[x]); else rotate(x);
        rotate(x);
      }
    }
  }
  
  void access(int x) {
    int y=0;
    while (x) {
      splay(x);
      ch[x][1]=y; update(x);
      y=x; x=f[x];
    }
  }
  
  void makeroot(int x) {
    access(x); splay(x); rev[x]^=1; pushr(x);
  }
  
  void link(int x,int y) {
    makeroot(x);
    f[x]=y;
  }
  void cut(int x,int y) {
    makeroot(x);
    access(y);
    splay(y);
    ch[y][opt(x)]=f[x]=0;
    update(y);
  }
  
  int query(int x,int y) {
    makeroot(x);
    access(y); splay(y);
    return poi[y];
  }
} lct;


void add_edge(int x) {
  lct.link(e[x].u,x+n);
  lct.link(e[x].v,x+n);
}

void del_edge(int x) {
  lct.cut(e[x].u,x+n);
  lct.cut(e[x].v,x+n);
}

void update(int cur){
  int p=lct.query(1,n);
  if (lct.b[p]+e[cur].a<ans) ans=lct.b[p]+e[cur].a;
}

int main(){
  scanf("%d %d",&n,&m);
  for (ri i=1;i<=m;i++) {
    scanf("%d %d %d %d",&e[i].u,&e[i].v,&e[i].a,&e[i].b);
  }
  sort(e+1,e+m+1);
  for (ri i=1;i<=m;i++) {
    lct.b[n+i]=e[i].b;
    lct.poi[n+i]=n+i;
  }
  set.clear();
  ans=987654321;
  
  for (ri i=1;i<=m;i++) if (e[i].u!=e[i].v) {
    int root1=set.findroot(e[i].u),root2=set.findroot(e[i].v);
    if (root1!=root2) {
      set.merge(root1,root2);
      add_edge(i);
      if (set.findroot(1)==set.findroot(n)) update(i);
    }
    else {
      int poi=lct.query(e[i].u,e[i].v);
      if (lct.b[poi]>e[i].b) {
        del_edge(poi-n);
        add_edge(i);
        if (set.findroot(1)==set.findroot(n)) update(i);
      }
    }
  }
  if (ans==987654321) puts("-1"); else cout<<ans<<endl;
}

 

posted @ 2019-08-28 14:31  HellPix  阅读(135)  评论(0编辑  收藏  举报