题目链接
https://www.lydsy.com/JudgeOnline/problem.php?id=3669
题解
将一个a-b,权值为c的边看成a-e-b,其中a,b权值为0,e的权值为c,这样就把边权变成了点权。
首先将所有边按照 Ai A i 排序,用LCT维护点和边的连通情况,边权为 Bi B i 。
考虑新加入一条从 x x 到,权值为 ai,bi a i , b i 的边。显然,如果这条边对 1 1 到的答案有影响,那么答案就可以对 ai+max(1→n的Bi) a i + max ( 1 → n 的 B i ) 取 min min 。如果这条边对答案没有影响,那么答案必定已经 ≤ ≤ 前述式子,对前述式子更新不会对答案有任何影响( ai a i 不是最小的, + + 号后面值的是相同的)。
- 如果与 y y 不连通,那么加入这条边不会对答案产生不利的影响。
- 如果与
y
y
连通,这个时候分两种情况考虑。
- 若到
y
y
的最大值
≤bi
≤
b
i
,加入这条边必定不会使
1
1
到的边权最大值变小,因此选择不加入。
- 若 x x 到的 Bi B i 最大值 >bi > b i ,此时删去 x x 到中边权最大的一个,必定不会使 1 1 到的边权最大值变大,因此可以这样操作。
可以证明,通过上述操作,得出的解一定是最优的。
代码
#include <cstdio> #include <algorithm> int read() { int x=0,f=1; char ch=getchar(); while((ch<'0')||(ch>'9')) { if(ch=='-') { f=-f; } ch=getchar(); } while((ch>='0')&&(ch<='9')) { x=x*10+ch-'0'; ch=getchar(); } return x*f; } const int maxn=50000; const int maxm=100000; const int maxk=maxn+maxm; const int inf=0x3f3f3f3f; struct node { node *son[2],*fa,*pos; int self,val,rev; }; node tree[maxk+10]; namespace lct { int isroot(node *x) { if(x->fa==NULL) { return 1; } return !((x->fa->son[0]==x)||(x->fa->son[1]==x)); } int t(node *x) { return x->fa->son[1]==x; } int pushdown(node *x) { if(x->rev) { x->rev=0; std::swap(x->son[0],x->son[1]); if(x->son[0]!=NULL) { x->son[0]->rev^=1; } if(x->son[1]!=NULL) { x->son[1]->rev^=1; } } return 0; } int updata(node *x) { int l=(x->son[0]==NULL)?0:x->son[0]->val,r=(x->son[1]==NULL)?0:x->son[1]->val; x->val=std::max(x->self,std::max(l,r)); x->pos=(x->self>=std::max(l,r))?x:((l>r)?x->son[0]->pos:x->son[1]->pos); return 0; } int rotate(node *x) { node *f=x->fa; pushdown(f); pushdown(x); int k=t(x); if(!isroot(f)) { f->fa->son[t(f)]=x; } x->fa=f->fa; f->fa=x; if(x->son[k^1]!=NULL) { x->son[k^1]->fa=f; } f->son[k]=x->son[k^1]; x->son[k^1]=f; updata(x); updata(f); return 0; } int splay_root(node *x) { while(!isroot(x)) { node *f=x->fa; if(isroot(f)) { rotate(x); } else if(t(f)==t(x)) { rotate(f); rotate(x); } else { rotate(x); rotate(x); } } pushdown(x); return 0; } int access(node *x) { node *y=NULL; while(x!=NULL) { splay_root(x); x->son[1]=y; if(y!=NULL) { y->fa=x; } updata(x); y=x; x=y->fa; } return 0; } int makeroot(node *x) { access(x); splay_root(x); x->rev^=1; return 0; } int link(node *x,node *y) { makeroot(x); x->fa=y; return 0; } int cut(node *x,node *y) { makeroot(x); access(y); splay_root(y); y->son[0]=x->fa=NULL; updata(y); return 0; } node* find(node *x) { access(x); splay_root(x); while(x->son[0]!=NULL) { x=x->son[0]; pushdown(x); } return x; } int check(node *x,node *y) { return find(x)==find(y); } node* getmax(node *x) { splay_root(x); int v=x->val; while(x!=NULL) { if(x->self==v) { return x; } if((x->son[0]!=NULL)&&(x->son[0]->val==v)) { x=x->son[0]; } else { x=x->son[1]; } pushdown(x); } return 0; } node* getpn(node *x,int op) { splay_root(x); x=x->son[op]; pushdown(x); while(x->son[op^1]!=NULL) { x=x->son[op^1]; pushdown(x); } return x; } int check_link(node *x,node *y,node *e) { if(check(x,y)) { makeroot(x); access(y); splay_root(y); if(y->val>e->self) { node *d=y->pos; node *p=getpn(d,0),*q=getpn(d,1); cut(d,p); cut(d,q); } else { return 0; } } link(e,x); link(e,y); return 0; } int getmax(node *x,node *y) { makeroot(x); access(y); splay_root(y); return y->val; } } struct edge { int x,y,a,b; bool operator <(const edge &other) const { if(a==other.a) { return b<other.b; } return a<other.a; } }; edge e[maxm+10]; int n,m; int main() { n=read(); m=read(); for(int i=1; i<=m; ++i) { e[i].x=read(); e[i].y=read(); e[i].a=read(); e[i].b=read(); } std::sort(e+1,e+m+1); for(int i=1; i<=n; ++i) { tree[i].son[0]=tree[i].son[1]=tree[i].fa=NULL; tree[i].self=tree[i].val=tree[i].rev=0; } int ans=inf; node *start=&tree[1],*end=&tree[n]; for(int i=1; i<=m; ++i) { tree[i+n].son[0]=tree[i+n].son[1]=tree[i+n].fa=NULL; tree[i+n].self=tree[i+n].val=e[i].b; tree[i+n].rev=0; node *l=&tree[e[i].x],*r=&tree[e[i].y],*ed=&tree[i+n]; lct::check_link(l,r,ed); if(lct::check(start,end)) { ans=std::min(ans,e[i].a+lct::getmax(start,end)); } } printf("%d\n",(ans==inf)?-1:ans); return 0; }
- 若到
y
y
的最大值
≤bi
≤
b
i
,加入这条边必定不会使
1
1
到的边权最大值变小,因此选择不加入。