[bzoj3669][NOI2014]魔法森林
2016-01-14 22:02
441 查看
题目大意
给定N个点M条边的无向图,每条边有两个权值a与b。求一条1到n的路径使得路径经过边的最大a与最大b的和最小。无法到达输出-1。n<=50000,m<=100000。
思想
我们尝试枚举路径的最大a值,那么我们只需按照a排序按顺序插入,维护1到n的b最大值即可。用并查集维护连通性。当加入j到k这条边时如果形成环,则删除环上的最大值。
我们用动态树来进行维护。
为了实现更易,将每条边看做一个点,例如第i条边两个端点是j与k,那么将i+n与j、k相连,权值放在代表边的点上。
参考程序
#include<cstdio> #include<algorithm> #include<stack> #include<cstring> #define fo(i,a,b) for(i=a;i<=b;i++) using namespace std; const int maxn=50000+10; stack<int> sta; struct dong{ int x,y,a,b; }; dong e[maxn*2]; int tree[maxn*3][2],key[maxn*3],father[maxn*3],num[maxn*3],pp[maxn*3],fa[maxn]; int i,j,k,l,t,n,m,ans; bool bz[maxn*3]; int Max(int a,int b){ if (key[a]>key[b]) return a;else return b; } int pd(int x){ if (tree[father[x]][0]==x) return 0;else return 1; } void update(int x){ num[x]=Max(x,Max(num[tree[x][0]],num[tree[x][1]])); } void rotate(int x){ int y=father[x],z=pd(x); tree[y][z]=tree[x][1-z]; if (tree[x][1-z]) father[tree[y][z]]=y; father[x]=father[y]; if (father[y]) tree[father[y]][pd(y)]=x; father[y]=x; tree[x][1-z]=y; update(y); update(x); if (pp[y]) pp[x]=pp[y],pp[y]=0; } void clear(int x){ if (bz[x]){ bz[x]=0; if (tree[x][0]) bz[tree[x][0]]^=1; if (tree[x][1]) bz[tree[x][1]]^=1; swap(tree[x][0],tree[x][1]); } } void romove(int x,int y){ while (x!=y){ sta.push(x); x=father[x]; } while (!sta.empty()){ clear(sta.top()); sta.pop(); } } void splay(int x,int y){ romove(x,y); while (father[x]!=y){ if (father[father[x]]!=y) if (pd(x)==pd(father[x])) rotate(x);else rotate(father[x]); rotate(x); } } void access(int x){ int y; splay(x,0); father[tree[x][1]]=0; if (tree[x][1]) pp[tree[x][1]]=x; tree[x][1]=0; update(x); while (pp[x]!=0){ y=pp[x]; splay(y,0); father[tree[y][1]]=0; if (tree[y][1]) pp[tree[y][1]]=y; tree[y][1]=x; father[x]=y; pp[x]=0; update(y); splay(x,0); } } void makeroot(int x){ access(x); splay(x,0); bz[x]^=1; } void link(int x,int y){ makeroot(x); access(y); splay(x,0); pp[x]=y; access(x); } void cut(int x,int y){ makeroot(x); access(y); splay(y,0); pp[y]=0; father[tree[y][0]]=0; if (tree[y][0]) tree[y][0]=0; update(y); } int getfa(int x){ return fa[x]?fa[x]=getfa(fa[x]):x; } bool cmp(dong a,dong b){ return a.a<b.a; } int main(){ scanf("%d%d",&n,&m); key[0]=-1;num[0]=0; fo(i,1,n) num[i]=i; fo(i,1,m) scanf("%d%d%d%d",&e[i].x,&e[i].y,&e[i].a,&e[i].b); sort(e+1,e+m+1,cmp); ans=10000000; fo(i,1,m){ j=e[i].x;k=e[i].y; if (getfa(j)==getfa(k)){ makeroot(j); access(k); splay(k,0); if (key[num[k]]>e[i].b){ l=num[k]; cut(l,e[l-n].x); cut(l,e[l-n].y); } else{ if (getfa(1)==getfa(n)){ makeroot(1); access(n); splay(n,0); ans=min(ans,e[i].a+key[num ]); } //printf("%d\n",i); continue; } } else fa[getfa(k)]=getfa(j); key[i+n]=e[i].b; num[i+n]=i+n; link(i+n,j); link(i+n,k); if (getfa(1)==getfa(n)){ makeroot(1); access(n); splay(n,0); ans=min(ans,e[i].a+key[num ]); } //printf("%d\n",i); } if (ans==10000000) ans=-1; printf("%d\n",ans); }
相关文章推荐
- teradata PI -- Join的影响
- 5分钟制作H5发光字表白并分享给她
- jfreechart绘制折线图(平面和3D)
- 给kill给一个小脚本
- Sublime Text 3 + OmniMarkupPreviewer体验略记
- leetcode笔记:Find Median from Data Stream
- Jquery中的(function($){...})(jQuery)
- MYSQL SHOW VARIABLES简介
- 解决当网络连接方式选择“桥接网卡”时,VirtualBox提示“未指定要bridged的网络界面”
- 利用pandas进行数据分组及可视化
- 银行家算法
- LeetCode 之 Best Time to Buy and Sell Stock II
- BZOJ 2324: [ZJOI2011]营救皮卡丘( floyd + 费用流 )
- 新工作 Day8
- python-列表与元组
- 示例演示“距离矢量路由算法”工作原理
- 运行时关联对象
- 初学java——java编程发展方向,JDK和Java源文件与Java字节码文件的关系
- 用keytool将eclipse下的apk签名文件转.p12文件步骤
- BZOJ 3343教主的魔法