BZOJ 3669 [Noi2014]魔法森林 ——SPFA / Link-Cut Tree
【题目分析】
大意就是有一张图,边权有两个值,ai和bi
找到一条路径,使得路径上的max(ai)+max(bi)最小。
遇到有两个权值或者多个权值的时候,如果他们互相影响,试着用分块搞一搞。
如果互不影响,先用排序搞掉一维。
这显然a与b分开计算,直接按照ai排序。
之后不断加入,然后计算在bi上的最短路,更新答案即可。
SPFA代码相当好写(复杂度一直是玄学如果重边比较多,几乎可以达到nm)
这么玄学的复杂度居然AC了,真实神奇。
#include <cstdio> #include <cstring> #include <cmath> #include <cstdlib> #include <map> #include <set> #include <queue> #include <string> #include <iostream> #include <algorithm> using namespace std; #define maxn 300005 #define inf 0x3f3f3f3f #define F(i,j,k) for (int i=j;i<=k;++i) #define D(i,j,k) for (int i=j;i>=k;--i) void Finout() { #ifndef ONLINE_JUDGE freopen("in.txt","r",stdin); // freopen("out.txt","w",stdout); #endif } int Getint() { int x=0,f=1; char ch=getchar(); while (ch<'0'||ch>'9') {if (ch=='-') f=-1; ch=getchar();} while (ch>='0'&&ch<='9') {x=x*10+ch-'0'; ch=getchar();} return x*f; } int n,m,dis[maxn],ans=inf; struct edge{int l,r,a,b;}e[maxn]; bool cmp(edge x,edge y) {return x.a<y.a;} int h[maxn<<1],ne[maxn<<1],to[maxn<<1],w[maxn<<1],en=0; void add(int a,int b,int c) { to[en]=b; w[en]=c; ne[en]=h[a]; h[a]=en++; to[en]=a; w[en]=c; ne[en]=h[b]; h[b]=en++; } int inq[maxn]; queue <int> q; void SPFA(int S) { while (!q.empty()) q.pop(); q.push(S); while (!q.empty()) { int x=q.front();q.pop();inq[x]=0; // cout<<"on "<<x<<endl; for (int i=h[x];i>=0;i=ne[i]) { if (dis[to[i]]>max(dis[x],w[i])) { dis[to[i]]=max(dis[x],w[i]); if (!inq[to[i]]) { inq[to[i]]=1; q.push(to[i]); } } } } } int main() { Finout(); n=Getint(); m=Getint(); F(i,1,m) { e[i].l=Getint(); e[i].r=Getint(); e[i].a=Getint(); e[i].b=Getint(); } sort(e+1,e+m+1,cmp); memset(h,-1,sizeof h); memset(dis,0x3f,sizeof dis); dis[1]=0; F(i,1,m) { add(e[i].l,e[i].r,e[i].b); SPFA(e[i].l);SPFA(e[i].r); ans=min(ans,dis[n]+e[i].a); } if (ans==inf) cout<<"-1"<<endl; else cout<<ans<<endl; }
之后想一想,用LCT去维护边权貌似复杂度更好。
也是按照ai排序,然后加入边,如果构成环,就删去权值最大的一个。
然后统计答案。
维护边权的时候,直接维护比较难,可以把原图边和点都看作点,然后互相连接,这样就只有点权了。
写起来也很爽。
#include <cstdio> #include <cstring> #include <cmath> #include <cstdlib> #include <map> #include <set> #include <queue> #include <string> #include <iostream> #include <algorithm> using namespace std; #define maxn 500005 #define inf 0x3f3f3f3f #define F(i,j,k) for (int i=j;i<=k;++i) #define D(i,j,k) for (int i=j;i>=k;--i) void Finout() { #ifndef ONLINE_JUDGE freopen("in.txt","r",stdin); // freopen("out.txt","w",stdout); #endif } int Getint() { int x=0,f=1; char ch=getchar(); while (ch<'0'||ch>'9') {if (ch=='-') f=-1; ch=getchar();} while (ch>='0'&&ch<='9') {x=x*10+ch-'0'; ch=getchar();} return x*f; } int mx[maxn],v[maxn],n,m,ans=inf,sta[maxn],top=0; int fa[maxn],ch[maxn][2],rev[maxn],val[maxn]; struct edge{int u,v,a,b;}e[maxn]; bool cmp(edge x,edge y){return x.a<y.a;} bool isroot(int x) {return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;} void update(int x) { mx[x]=x; if (val[mx[ch[x][0]]]>val[mx[x]]) mx[x]=mx[ch[x][0]]; if (val[mx[ch[x][1]]]>val[mx[x]]) mx[x]=mx[ch[x][1]]; } void pushdown(int x) { if (rev[x]) { rev[x]^=1; rev[ch[x][0]]^=1; rev[ch[x][1]]^=1; swap(ch[x][0],ch[x][1]); } } void rot(int x) { int y=fa[x],z=fa[y],l,r; if (ch[y][0]==x) l=0; else l=1; r=l^1; if (!isroot(y)) { if (ch[z][0]==y) ch[z][0]=x; else ch[z][1]=x; } fa[x]=z; fa[y]=x; fa[ch[x][r]]=y; ch[y][l]=ch[x][r]; ch[x][r]=y; update(y);update(x); } void splay(int x) { top=0;sta[++top]=x; for (int i=x;!isroot(i);i=fa[i]) sta[++top]=fa[i]; while (top) pushdown(sta[top--]); while (!isroot(x)) { int y=fa[x],z=fa[y]; if (!isroot(y)) { if (ch[y][0]==x^ch[z][0]==y) rot(y); else rot(x); } rot(x); } } void access(int x) { for (int t=0;x;t=x,x=fa[x]) splay(x),ch[x][1]=t,update(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); if (ch[y][0]==x) { ch[y][0]=x; fa[x]=0; } } int query(int x,int y) { makeroot(x); access(y); splay(y); return mx[y]; } int main() { Finout(); val[0]=-inf; n=Getint();m=Getint(); F(i,1,n) val[i]=-inf; F(i,1,m) { e[i].u=Getint(); e[i].v=Getint(); e[i].a=Getint(); e[i].b=Getint(); } sort(e+1,e+m+1,cmp); F(i,1,m) { int l=e[i].u,r=e[i].v,a=e[i].a,b=e[i].b; int flag=0; // cout<<l<<" "<<r<<" "<<a<<" "<<b<<endl; if (find(l)==find(r)) { int tmp=query(l,r); if (val[tmp]>b) { // cout<<"cut "<<tmp<<" "<<e[tmp-n].v<<" "<<e[tmp-n].u<<endl; cut(tmp,e[tmp-n].v); cut(tmp,e[tmp-n].u); flag=1; } else { // cout<<"cal"<<endl; if (find(1)==find(n)) { ans=min(ans,a+val[query(1,n)]); continue; } } } else flag=1; if (flag) { // cout<<"link"<<endl; link(l,n+i);link(r,n+i); val[n+i]=e[i].b; mx[n+i]=n+i; } if (find(1)==find(n)) { // cout<<"cal"<<endl; ans=min(ans,a+val[query(1,n)]); } } if (ans==inf) cout<<"-1"<<endl; else cout<<ans<<endl; }