题目
Description
异变又发生了,魂魄妖梦作为幻想乡的一名自(cheng)机(guan),主动前去解决异变。
我们用一个n个点、m条边的无向联通图来表示妖梦可选择的路线,妖梦从白玉楼出发,白玉楼被视为编号为1的点,编号为2——n的点是幻想乡的村庄,其中编号为n的村庄发生了异变。
每条边上可能会有一些妖怪袭击人类(然而妖梦是半人半灵),所以对于第i条边,妖梦需要t[i]分钟通过这条路。妖梦带了她的人符[现世斩],可以使所有连接点x的边的通过时间变成1(x可以任意指定)。然而为了保留足够的力量解决异变,妖梦只会用这个符卡一次。妖梦想知道,她到达村庄n的最短时间是多少。
Input
第一行两个整数n,m。接下来m行,每行三个整数u[i],v[i],t[i],表示这条无向边连接点u[i],v[i],通过时间为t[i]。
Output
一个整数,表示妖梦到达村庄的最短时间。
Sample Input
5 5
1 2 3
2 3 3
3 5 2
2 4 1
4 5 4
Sample Output
4
Data Constraint
40%:n≤1000 m≤5000
100%:2≤n≤100,000 n-1≤m≤500,000 1≤t[i]≤1,000,000,000
可能有重边和自环,保证能从1到n
Hint
当x=1,最短路径长度为6:1->2->3->5或1->2->4->5
当x=2,最短路径长度为4:1->2->3->5
当x=3,最短路径长度为5:1->2->3->5
当x=4,最短路径长度为5:1->2->4->5
当x=5,最短路径长度为5:1->2->4->5
分析
这题让我们想到了GDOI2016的SigemaGO
我们知道修改过后的X一定是在答案的最短路上面的,也就是说,修改这个X的影响是:
原来这条路径上面上,连接某个点的两条边的权值变为1。
现在题目就变为:如果有一个三元组a,b,c,a到b有一条有向边,b到c有一条有向边,
若对点b使用一次【现世斩】,就可以是得a到c之间产生一条权值为2的有向边。
解法
现在就可以用分层SPFA来解决。
我们先把图分成三层,第一层是原图,第二层是用来衔接第一、第三层,第三层跟第一层一样。
层与层之间的边权为1。
code
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string.h>
#include <cmath>
#include <math.h>
#define ll long long
using namespace std;
struct arr{
int x,y;
ll z;
}aa[500003];
int a[4000003],next[4000003];
ll v[4000003];
int b[300003];
ll dis[900003];
int n,m,x,y,tot;
ll z;
int data[8000003];
bool bz[300003];
void read(int &n)
{
char ch=getchar();
while(ch==' ' || ch=='\n') ch=getchar();int q=0;
while(ch>='0' && ch<='9' ) {q=q*10+ch-48;ch=getchar( );}n=q;
}
void read1(ll &n)
{
char ch=getchar();
while(ch==' ' || ch=='\n') ch=getchar();ll q=0;
while(ch>='0' && ch<='9' ) {q=q*10+ch-48;ch=getchar( );}n=q;
}
void add(int x,int y,ll z)
{
tot++;
next[tot]=b[x];
a[tot]=y;
v[tot]=z;
b[x]=tot;
}
bool cmp(arr x,arr y)
{
return((x.x<y.x)||((x.x==y.x)&&(x.y<y.y))||((x.x==y.x)&&(x.y==y.y)&&(x.z<y.z)));
}
void spfa(int x)
{
memset(dis,127,sizeof(dis));
memset(bz,1,sizeof(bz));
int i=0,j=1;
dis[x]=0;
data[1]=x;
bz[x]=0;
while(i<j)
{
i++;
for(int k=b[data[i]];k;k=next[k])
{
if(dis[data[i]]+v[k]<dis[a[k]])
{
dis[a[k]]=dis[data[i]]+v[k];
if(bz[a[k]])
{
bz[a[k]]=0;
j++;
data[j]=a[k];
}
}
}
bz[data[i]]=1;
}
}
int main()
{
freopen("cut.in","r",stdin);
freopen("cut.out","w",stdout);
//scanf("%d%d",&n,&m);
read(n);
read(m);
for(int i=1;i<=m;i++)
{
//scanf("%d%d%lld",&aa[i].x,&aa[i].y,&aa[i].z);
read(aa[i].x);
read(aa[i].y);
read1(aa[i].z);
}
sort(aa+1,aa+1+m,cmp);
for(int i=1;i<=m;i++)
if((aa[i].x!=aa[i-1].x)||((aa[i].y!=aa[i-1].y)))
{
add(aa[i].x,aa[i].y,aa[i].z);
add(aa[i].y,aa[i].x,aa[i].z);
add(n+n+aa[i].x,n+n+aa[i].y,aa[i].z);
add(n+n+aa[i].y,n+n+aa[i].x,aa[i].z);
add(aa[i].x,aa[i].y+n,1);
add(aa[i].y,aa[i].x+n,1);
add(aa[i].x+n,aa[i].y+n+n,1);
add(aa[i].y+n,aa[i].x+n+n,1);
}
spfa(1);
ll ans=min(dis[n],dis[n+n]);
ans=min(ans,dis[n+n+n]);
spfa(1+n);
printf("%lld\n",min(ans,dis[n+n+n]));
}