bzoj4289(神建图+最短路)

再学一个建图姿势。。

可以把边看成点,然后有公共点的边相互连边,跑最短路就可以了。。

然而菊花图会退化成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

 

[Submit][Status][Discuss]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值