【BZOJ 3669】 [Noi2014]魔法森林 LCT维护动态最小生成树
这道题看题意是在求一个二维最小瓶颈路,唯一可行方案就是枚举一维在这一维满足的条件下使另一维最小,那么我们就把第一维排序利用A小的边在A大的情况下仍成立来动态加边维护最小生成树。
#include <cstdio> #include <algorithm> namespace Pre{ inline void read(int &sum){ register char ch=getchar(); for(sum=0;ch<'0'||ch>'9';ch=getchar()); for(;ch>='0'&&ch<='9';sum=(sum<<1)+(sum<<3)+ch-'0',ch=getchar()); } const int N=50010; const int M=100010; const int Inf=0x7f7f7f7f; int A[M],B[M],ans=Inf,X[M],Y[M],n,m,e[M]; inline bool comp(int a,int b){ return A[a]<A[b]; } inline int Max(int x,int y){ return x>y?x:y; } inline int Min(int x,int y){ return x<y?x:y; } } namespace LCT{ const int MN=150020; struct Node{ Node *ch[2],*f; int id,rid; bool rev; inline void pushup(){ using Pre::B; id=B[ch[0]->id]>B[ch[1]->id]?ch[0]->id:ch[1]->id; id=B[id]>B[rid]?id:rid; } inline void pushdown(); }null[MN]; inline void Swap(Node *&a,Node *&b){ Node *c=a; a=b; b=c; } inline void Node:: pushdown(){ if(!rev)return; Swap(ch[0],ch[1]); ch[0]->rev^=1; ch[1]->rev^=1; rev=0; } inline void Init(){ using namespace Pre; null->ch[0]=null->ch[1]=null->f=null; for(int i=1;i<=n;i++) null[i].ch[0]=null[i].ch[1]=null[i].f=null,null[i].id=null[i].rid=0; for(int i=n+1;i<=n+m;i++) null[i].ch[0]=null[i].ch[1]=null[i].f=null,null[i].id=null[i].rid=i-n; } inline int get(Node *p){ return p->f->ch[1]==p; } inline bool isroot(Node *p){ return p->f->ch[0]!=p&&p->f->ch[1]!=p; } inline void rotate(Node *p){ Node *fa=p->f,*pa=fa->f; int j=get(p); if(!isroot(fa))pa->ch[get(fa)]=p; if((fa->ch[j]=p->ch[j^1])!=null)fa->ch[j]->f=fa; fa->f=p; p->ch[j^1]=fa; p->f=pa; fa->pushup(); p->pushup(); } inline void spaly(Node *p){ p->pushdown(); for(Node *fa=p->f;!isroot(p);rotate(p),fa=p->f) if(!isroot(fa)){ fa->f->pushdown(),fa->pushdown(),p->pushdown(); rotate(get(fa)==get(p)?fa:p); }else fa->pushdown(),p->pushdown(); } inline void expose(Node *p){ Node *y=null; while(p!=null){ spaly(p); p->ch[1]=y; p->pushup(); y=p; p=p->f; } } inline void make_root(Node *p){ expose(p); spaly(p); p->rev^=1; } inline Node *find_root(Node *p){ expose(p); spaly(p); while(p->ch[0]!=null) p=p->ch[0],p->pushdown(); return p; } inline void link(Node *a,Node *b){ make_root(a); a->f=b; } inline void cut(Node *a,Node *b){ make_root(a); expose(b); spaly(b); b->ch[0]->f=null; b->ch[0]=null; b->pushup(); } inline void Link(int a,int b){ link(null+a,null+b); } inline void Cut(int a,int b){ cut(null+a,null+b); } inline int find(int x){ return find_root(null+x)-null; } inline int query(int a,int b){ Node *x=null+a,*y=null+b; make_root(x); expose(y); spaly(y); return Pre::B[y->id]; } inline int query_id(int a,int b){ Node *x=null+a,*y=null+b; make_root(x); expose(y); spaly(y); return y->id; } } inline void Init(){ using namespace Pre; read(n),read(m); for(int i=1;i<=m;i++) read(X[i]),read(Y[i]),read(A[i]),read(B[i]),e[i]=i; std::sort(e+1,e+m+1,comp); LCT::Init(); } inline void Work(){ using namespace Pre; using LCT::find; using LCT::query; using LCT::Link; using LCT::Cut; using LCT::query_id; for(int i=1;i<=m;i++) if(find(X[e[i]])!=find(Y[e[i]])){ Link(e[i]+n,X[e[i]]),Link(e[i]+n,Y[e[i]]); if(find(1)==find(n)) ans=Min(query(1,n)+A[e[i]],ans); }else if(query(X[e[i]],Y[e[i]])>B[e[i]]){ int temp=query_id(X[e[i]],Y[e[i]]); Cut(temp+n,X[temp]),Cut(temp+n,Y[temp]); Link(e[i]+n,X[e[i]]),Link(e[i]+n,Y[e[i]]); if(find(1)==find(n)) ans=Min(ans,query(1,n)+A[e[i]]); } } int main(){ using namespace Pre; Init(),Work(); printf("%d",ans==Inf?-1:ans); return 0; }
苟利国家生死以, 岂因祸福避趋之。