标签:bzoj bzoj3669 noi2014 魔法森林 spfa
题目大意:
给定一个无向图,每条边有两个权值ai和bi,从1走到N,设路径上a权的最大值为A,b权的最大值为B,求A+B的最小值
首先这题如果只有一个权值就是水题无误……但是多了个权值之后我们就要好好考虑一下了
我们对a排序,枚举a,对于每一次枚举求b权最大值的最小值即可
跑M遍SPFA肯定超时无误 网上很多人写了LInk-Cut-Tree维护动态最小生成树 我的LCT没写明白 就去写了SPFA。。。。
这里要用的SPFA的动态加点(边)法 我们每加一条边 就把边的两端点入队 继续SPFA 不用对f数组进行memset
这方法非常快 比LCT好写了不知多少 然后这里还有剪枝
剪枝1 每加一条边就SPFA自然很浪费 我们发现数据里有a<=30的点 那么很多边的a值会是重复的 我们把a值相同的点统统加入队列 然后SPFA一次解决
剪枝2 对于一条双向边 我们不必向队列中加两个点 我一开始写的是把f值小的加进去 因为小的可以更新大的 后来发现这样还是慢 就直接在主函数中更新f值大的 能更新就加入队列
然后加上堆优化和读入优化 代码就排第一了。。。跑了1400+MS 喵哈哈哈哈哈
#include<ctime> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define M 50500 using namespace std; struct abcd{ int to,f,next; }table[M<<2]; int head[M],tot; struct edges{ int x,y,a,b; }e[M<<1]; bool operator <(edges x,edges y) { return x.a < y.a ; } int n,m,ans=0x3f3f3f3f,f[M],heap[M],pos[M],top; void push_up(int x) { int t=pos[x]; while(t>1&&f[heap[t]]<f[heap[t>>1]]) swap(heap[t],heap[t>>1]),swap(pos[heap[t]],pos[heap[t>>1]]),t>>=1; } void insert(int x) { heap[++top]=x; pos[x]=top; push_up(x); } void pop() { pos[heap[1]]=0; heap[1]=heap[top]; heap[top--]=0; pos[heap[1]]=1; int t=2; while(t<=top) { if(t<top&&f[heap[t]]>f[heap[t+1]]) t++; if(f[heap[t]]<f[heap[t>>1]]) swap(heap[t],heap[t>>1]),swap(pos[heap[t]],pos[heap[t>>1]]),t<<=1; else break; } } void SPFA() { int i; while(top) { int x=heap[1];pop(); for(i=head[x];i;i=table[i].next) if(f[table[i].to]>max(f[x],table[i].f)) { f[table[i].to]=max(f[x],table[i].f); if(!pos[table[i].to]) insert(table[i].to); else push_up(table[i].to); } } } void add(int x,int y,int z) { table[++tot].to=y; table[tot].f=z; table[tot].next=head[x]; head[x]=tot; } char c; inline void scan(int &x) { x=0; do c=getchar(); while(c<'0'||c>'9'); while(c>='0'&&c<='9')x*=10,x+=c-'0',c=getchar(); } int main() { //freopen("forest.in","r",stdin); //freopen("forest.out","w",stdout); int i; cin>>n>>m; for(i=1;i<=m;i++) scan(e[i].x),scan(e[i].y),scan(e[i].a),scan(e[i].b); sort(e+1,e+m+1); memset(f,0x3f,sizeof f); f[1]=0; for(i=1;i<=m;i++) { add(e[i].x,e[i].y,e[i].b); add(e[i].y,e[i].x,e[i].b); if(f[e[i].x]>f[e[i].y]) swap(e[i].x,e[i].y); if(max(f[e[i].x],e[i].b)<f[e[i].y]) f[e[i].y]=max(f[e[i].x],e[i].b),insert(e[i].y); if(e[i].a!=e[i+1].a) SPFA(); ans=min(ans,e[i].a+f[n]); } if(ans==0x3f3f3f3f) cout<<-1<<endl; else cout<<ans<<endl; return 0; }
标签:bzoj bzoj3669 noi2014 魔法森林 spfa
原文地址:http://blog.csdn.net/popoqqq/article/details/38978675