再学一个建图姿势。。
可以把边看成点,然后有公共点的边相互连边,跑最短路就可以了。。
然而菊花图会退化成m^2,需要再优化。。
把无向边拆成2个有向边,对每个点存入边和出边,然后出边之间做个差分,即对出边的边权排序,然后相邻边之间连边,小边向大边连权值为2边权值之差的边,大边向小边连权值为0的边,这样入边只需向他的对应边连一个权值为原边权的边即可达到去最大值的效果。
然后剩下起点和终点就直接想对应的出边和入边连边就行了,边权为原图的边权。。
/**
* ┏┓ ┏┓
* ┏┛┗━━━━━━━┛┗━━━┓
* ┃ ┃
* ┃ ━ ┃
* ┃ > < ┃
* ┃ ┃
* ┃... ⌒ ... ┃
* ┃ ┃
* ┗━┓ ┏━┛
* ┃ ┃ Code is far away from bug with the animal protecting
* ┃ ┃ 神兽保佑,代码无bug
* ┃ ┃
* ┃ ┃
* ┃ ┃
* ┃ ┃
* ┃ ┗━━━┓
* ┃ ┣┓
* ┃ ┏┛
* ┗┓┓┏━┳┓┏┛
* ┃┫┫ ┃┫┫
* ┗┻┛ ┗┻┛
*/
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<cmath>
#include<map>
#include<stack>
#include<set>
#include<bitset>
#define inc(i,l,r) for(int i=l;i<=r;i++)
#define dec(i,l,r) for(int i=l;i>=r;i--)
#define link(x) for(edge *j=h[x];j;j=j->next)
#define mem(a) memset(a,0,sizeof(a))
#define ll long long
#define eps 1e-12
#define succ(x) (1<<x)
#define lowbit(x) (x&(-x))
#define sqr(x) ((x)*(x))
#define mid (x+y>>1)
#define NM 400005
#define nm 2000005
#define pi 3.1415926535897931
const ll inf=1e16+7;
using namespace std;
ll read(){
ll x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return f*x;
}
struct edge{int t,v;edge*next;}e[nm],*h[NM],*o=e;
void add(int x,int y,int v){o->v=v;o->t=y;o->next=h[x];h[x]=o++;}
struct tmp{
int i;ll v;
bool operator<(const tmp&o)const{return v>o.v;}
};
priority_queue<tmp>q;
vector<tmp>c[NM],b[NM];
ll d[NM];
int n,m,_x,_y,_t;
void dij(){
inc(i,1,2*m+1)d[i]=inf;
q.push(tmp{0,0});
while(!q.empty()){
int t=q.top().i;q.pop();
link(t)if(d[j->t]>d[t]+j->v)q.push(tmp{j->t,d[j->t]=d[t]+j->v});
}
}
int main(){
n=read();m=read();
inc(i,1,m){
_x=read();_y=read();_t=read();
add(i+m,i,_t);add(i,i+m,_t);
c[_x].push_back(tmp{i,_t});b[_x].push_back(tmp{i+m,_t});
c[_y].push_back(tmp{i+m,_t});b[_y].push_back(tmp{i,_t});
}
inc(i,1,n){
sort(c[i].begin(),c[i].end());sort(b[i].begin(),b[i].end());
int cnt=c[i].size()-1;
inc(j,0,cnt-1)add(c[i][j].i,c[i][j+1].i,0),add(c[i][j+1].i,c[i][j].i,c[i][j].v-c[i][j+1].v);
}
add(0,c[1][c[1].size()-1].i,c[1][c[1].size()-1].v);
_x=b[n].size()-1;
inc(i,0,_x)add(b[n][i].i,m*2+1,b[n][i].v);
dij();
return 0*printf("%lld\n",d[2*m+1]);
}
4289: PA2012 Tax
Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 1141 Solved: 338
[Submit][Status][Discuss]
Description
给出一个N个点M条边的无向图,经过一个点的代价是进入和离开这个点的两条边的边权的较大值,求从起点1到点N的最小代价。起点的代价是离开起点的边的边权,终点的代价是进入终点的边的边权
N<=100000
M<=200000
Input
Output
Sample Input
4 5
1 2 5
1 3 2
2 3 1
2 4 4
3 4 8
Sample Output
12
HINT
Source