1. 程式人生 > >NOI2014魔法森林

NOI2014魔法森林

.org make lin tps 生成樹 bool std swap pair

題目鏈接

把邊按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(‘\n‘) #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]; 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; } /* */

NOI2014魔法森林