题目大意:给一个无向图,每个边有两个权值,a和b,要想经过这条边,身上所携带的a和b都需要大于等于边的权值,否则就会遭到攻击。求从1到n身上携带最少的a+b的值
思路:1、LCT(不会)
2、弱弱的用最短路。
利用SPFA求从起点到终点的最短最长距离是肯定能想到的,但是跑m次SPFA是肯定会超时的。
有一个十分神奇的想法,按照a的权值排序,从小到大一次将每一条边加入到图中,然后跑SPFA。dis数组不用清极大值,每次SPFA时只向队列里加入新加入的边的两个端点。这是两个很有效的剪枝。
CODE(不加堆优化,BZOJ3880ms):
#include <queue> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define MAX 600010 #define INF 0x7f7f7f7f using namespace std; queue<int> q; struct Complex{ int x,y; int a,b; bool operator <(const Complex& x)const { return a < x.a; } }edge[MAX]; int points,edges; int ans = INF; int head[MAX],total; int next[MAX],aim[MAX],length[MAX]; int f[MAX]; bool v[MAX]; inline void Add(int x,int y,int len); void SPFA(); int main() { cin >> points >> edges; for(int i = 1;i <= edges; ++i) scanf("%d%d%d%d",&edge[i].x,&edge[i].y,&edge[i].a,&edge[i].b); sort(edge + 1,edge + edges + 1); memset(f,0x3f,sizeof(f)); f[1] = 0; for(int i = 1;i <= edges; ++i) { Add(edge[i].x,edge[i].y,edge[i].b); Add(edge[i].y,edge[i].x,edge[i].b); q.push(edge[i].x),v[edge[i].x] = true; q.push(edge[i].y),v[edge[i].y] = true; if(edge[i].a != edge[i + 1].a) SPFA(); ans = min(ans,edge[i].a + f[points]); } if(ans >= 0x3f3f3f3f) ans = -1; cout << ans; return 0; } inline void Add(int x,int y,int len) { next[++total] = head[x]; aim[total] = y; length[total] = len; head[x] = total; } void SPFA() { while(!q.empty()) { int x = q.front(); q.pop(); v[x] = false; for(int i = head[x];i;i = next[i]) if(f[aim[i]] > max(length[i],f[x])) { f[aim[i]] = max(length[i],f[x]); if(!v[aim[i]]) q.push(aim[i]); } } }
#include <queue> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define MAX 600010 #define INF 0x7f7f7f7f using namespace std; struct Point; priority_queue<Point> q; struct Complex{ int x,y; int a,b; bool operator <(const Complex& x)const { return a < x.a; } }edge[MAX]; struct Point{ int p; Point(int a):p(a) {} bool operator <(const Point& a)const; }; int points,edges; int ans = INF; int head[MAX],total; int next[MAX],aim[MAX],length[MAX]; int f[MAX]; bool v[MAX]; inline void Add(int x,int y,int len); void SPFA(); int main() { //freopen("a.in","r",stdin); //freopen("a.out","w",stdout); cin >> points >> edges; for(int i = 1;i <= edges; ++i) scanf("%d%d%d%d",&edge[i].x,&edge[i].y,&edge[i].a,&edge[i].b); sort(edge + 1,edge + edges + 1); memset(f,0x3f,sizeof(f)); f[1] = 0; for(int i = 1;i <= edges; ++i) { Add(edge[i].x,edge[i].y,edge[i].b); Add(edge[i].y,edge[i].x,edge[i].b); q.push(Point(edge[i].x)),v[edge[i].x] = true; q.push(Point(edge[i].y)),v[edge[i].y] = true; if(edge[i].a != edge[i + 1].a) SPFA(); ans = min(ans,edge[i].a + f[points]); } if(ans >= 0x3f3f3f3f) ans = -1; cout << ans; return 0; } inline void Add(int x,int y,int len) { next[++total] = head[x]; aim[total] = y; length[total] = len; head[x] = total; } void SPFA() { while(!q.empty()) { Point x = q.top(); q.pop(); v[x.p] = false; for(int i = head[x.p];i;i = next[i]) if(f[aim[i]] > max(length[i],f[x.p])) { f[aim[i]] = max(length[i],f[x.p]); if(!v[aim[i]]) q.push(Point(aim[i])); } } } bool Point :: operator <(const Point& a)const { return f[a.p] < f[p]; }