您的位置:首页 > 其它

BZOJ 4289: PA2012 Tax

2016-08-08 15:59 351 查看
Description

给出一个N个点M条边的无向图,经过一个点的代价是进入和离开这个点的两条边的边权的较大值,求从起点1到点N的最小代价。起点的代价是离开起点的边的边权,终点的代价是进入终点的边的边权

N<=100000 M<=200000

Solution

神题搞得我欲仙欲死,竟不知从何说起

看到这题第一反应是直接跑最短路,但并过不了

所以考虑重新构图

显然按边构图(把边作为新图中的点)大法好

首先先把无向边都搞成有向边

采用网络流的思想,我们对于以x为起点的有向边,我们把这些边按照边权从小到大排序,然后依次(排序后相邻的)连边,比他大的连边权为原边权差的边,小的连边权为0的边。

然后所有正向边和反向边之间互相连边,边权为原边边权的大小

设立一个虚拟源点和虚拟汇点,源点向所有以1为起点的边连边,所有以n为终点的边向汇点连边,边权都为原边权。

这样的正确性是显然的(画个图可以知道)

而边的个数级别是O(m)的

最后跑src到sink的最短路即可

Code

/**************************************************************
Problem: 4289
User: bblss123
Language: C++
Result: Accepted
Time:3468 ms
Memory:43160 kb
****************************************************************/

#include<iostream>
#include<string.h>
#include<stdio.h>
#include<algorithm>
#include<time.h>
#include<stdlib.h>
#include<math.h>
#include<string>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
typedef double db;
typedef unsigned ud;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef vector<int> vec;
typedef vector<pii> vecp;

#define fi first
#define se second
#define pb push_back
#define ph push

const int INF=(ud)-1>>1;
const ll inf=(ull)-1ll>>1;

template<class T>void rd(T &a){
a=0;char c;
while(c=getchar(),!isdigit(c));
do a=a*10+(c^48);
while(c=getchar(),isdigit(c));
}
template<class T>void nt(T x){
if(!x)return;
nt(x/10);
putchar(48+x%10);
}
template<class T>void pt(T x){
if(!x)putchar('0');
else nt(x);
}
template<class T>void Max(T &a,T b){
if(a<b)a=b;
}
template<class T>void Min(T &a,T b){
if(a==-1||a>b)a=b;
}
const int M=1e5+5;
const int N=2e5+5;
struct Slide{
int a,b,c;
}slid[N<<1];
struct node{
int to;ll v;
inline bool operator < (const node &tmp)const{
return v>tmp.v;
}
};
int que[M];
struct Edge{
int to,c,nxt;
}G[N<<2];
int head
,tot_edge;
inline void add_edge(int from,int to,int c){
G[tot_edge]=(Edge){to,c,head[from]};
head[from]=tot_edge++;
G[tot_edge]=(Edge){from,c,head[to]};
head[to]=tot_edge++;
}
inline bool cmp(const int &a,const int &b){
return slid[a].c<slid[b].c;
}
vector<node>edge[N<<1];
int src,sink,n,m,cnt;
priority_queue<node>pque;
ll d[N<<1];
bool mark[N<<1];
inline ll Djstl(){
for(int i=0;i<=sink;++i)
d[i]=inf;
for(pque.ph((node){src,d[src]=0});!pque.empty();){
node now=pque.top();pque.pop();
int v=now.to;
if(v==sink)return now.v;
if(mark[v])continue;
mark[v]=1;
for(int i=0;i<edge[v].size();++i){
node nxt=edge[v][i];
if(d[nxt.to]>d[v]+nxt.v){
d[nxt.to]=d[v]+nxt.v;
pque.ph((node){nxt.to,d[nxt.to]});
}
}
}
}
int main(){
cin>>n>>m;
memset(head,-1,sizeof(head));
tot_edge=0;
for(int i=1,a,b,c;i<=m;++i){
rd(a),rd(b),rd(c);
slid[cnt++]=(Slide){a,b,c};
slid[cnt++]=(Slide){b,a,c};
add_edge(a,b,c);
}
for(int i=1;i<=n;++i){
int s=0;
for(int j=head[i];~j;j=G[j].nxt)
que[s++]=j;//这些点是以i为起点的边的编号
for(int j=0;j<s;++j)
edge[que[j]].pb((node){que[j]^1,slid[que[j]].c});
sort(que,que+s,cmp);
for(int j=0;j<s-1;++j){
edge[que[j]].pb((node){que[j+1],slid[que[j+1]].c-slid[que[j]].c});
edge[que[j+1]].pb((node){que[j],0});
}
}
src=cnt,sink=src+1;
for(int i=0;i<cnt;++i){
if(slid[i].a==1)edge[src].pb((node){i,slid[i].c});
if(slid[i].b==n)edge[i].pb((node){sink,slid[i].c});
}
cout<<Djstl()<<endl;
return 0;
}


太弱啦这种题写了好多天(虽说中间放假了)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  BZOJ 最短路 构图