[BZOJ3669][Noi2014]魔法森林(动态spfa)

来源:互联网 发布:紫牛软件 编辑:程序博客网 时间:2024/05/16 01:07

题目:

我是超链接

题解:

据说正解是LCT???这跟LCT有什么关系
想了想觉得可以用动态加点的spfa做
要是想求两个值的最小和,那我们先按照一个(a[i])排序,然后用spfa跑路上(b[i])最大值。
动态加边,如果这条边能对现状有什么改变的话,那一定是从这两个端点出发了
dis数组并不用每次都赋成INF,因为对现状的改变一定是改的越来越好不会越来越倒退啊,然后用大脑想想都知道每次都memset肯定T到没边

代码:

#include <queue>#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#define INF 1e9using namespace std;const int N=50005;const int M=200005;int tot,nxt[M],point[N],v[M],dis[N],cb[M];bool vis[N];struct hh{int x,y,a,b;}e[M];queue<int>q;int cmp(hh a,hh b){return a.a<b.a;}void addline(int x,int y,int z){    ++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y; cb[tot]=z;    ++tot; nxt[tot]=point[y]; point[y]=tot; v[tot]=x; cb[tot]=z;}void spfa(int x,int y){       q.push(x); q.push(y);    while (!q.empty())    {        int now=q.front(); q.pop(); vis[now]=0;        for (int i=point[now];i;i=nxt[i])          if (dis[v[i]]>max(dis[now],cb[i]))          {            dis[v[i]]=max(dis[now],cb[i]);            if (!vis[v[i]]) q.push(v[i]),vis[v[i]]=1;          }    }}int main(){    int n,m,i;    scanf("%d%d",&n,&m);    memset(dis,0x7f,sizeof(dis));    dis[1]=0;    for(i=1;i<=m;i++) scanf("%d%d%d%d",&e[i].x,&e[i].y,&e[i].a,&e[i].b);    sort(e+1,e+m+1,cmp);    int ans=INF+1;    for (i=1;i<=m;i++)    {        addline(e[i].x,e[i].y,e[i].b);        spfa(e[i].x,e[i].y);        ans=min(ans,dis[n]+e[i].a);    }    if (ans>INF) printf("-1");else printf("%d",ans);}
原创粉丝点击