2018.12.30-dtoj-2659-Tax
阿新 • • 發佈:2018-12-30
img namespace hid nbsp ack ont dto printf 大小 以下代碼:
題目描述:
給出一個N個點M條邊的無向圖,經過一個點的代價是進入和離開這個點的兩條邊的邊權的較大值,求從起點1到點N的最小代價。起點的代價是離開起點的邊的邊權,終點的代價是進入終點的邊的邊權 N<=100000 M<=200000算法標簽:dijk,建邊優化
思路:
考慮重新建圖,容易想到把兩條邊合成一條邊,邊權是兩邊之間的最大值,這樣邊的條數是m2 跑不過,考慮優化建邊。對於每個頂點,我們僅把這個點的入邊與和我大小相同的出邊相連,因為我們把雙向邊拆成單向邊,所以必然存在與自己的大小相等的出邊。再把每條出邊像比自己小的邊連0,比自己大的邊連權值的差值,這麽建邊條數是m級別的。以下代碼:
#include<bits/stdc++.h> #define il inline #define LL long long #define _(d) while(d(isdigit(ch=getchar()))) using namespace std; const int N=4e5+5,M=4e6+5; struct node{int x,v;};vector<node> v[N]; int n,m,s,t,head[N],ne[M],to[M],w[M],cnt;LL d[N]; struct data{int x;LL d;boolView Codeoperator<(const data&t1)const{return d>t1.d;};}; bool cmp(node t1,node t2){return t1.v<t2.v;}priority_queue<data> q; il int read(){int x;char ch;_(!);x=ch^48;_()x=(x<<1)+(x<<3)+(ch^48);return x;} il void insert(int x,int y,int z){ne[++cnt]=head[x];head[x]=cnt;to[cnt]=y;w[cnt]=z;} ilvoid dijk(){ for(int i=1;i<=t;i++)d[i]=1e18;q.push((data){s,0}); while(!q.empty()){ data now=q.top();q.pop();int x=now.x;if(now.d!=d[x])continue; for(int i=head[x];i;i=ne[i]) if(d[to[i]]>d[x]+w[i])d[to[i]]=d[x]+w[i],q.push((data){to[i],d[to[i]]}); } } int main() { n=read();m=read();s=0;t=2*m+1; for(int i=1;i<=m;i++){ int x=read(),y=read(),z=read(); v[x].push_back((node){i,z}); v[y].push_back((node){i+m,z}); insert(i,i+m,z);insert(i+m,i,z); } for(int i=0;i<v[1].size();i++)insert(s,v[1][i].x,v[1][i].v); for(int i=0;i<v[n].size();i++)insert(v[n][i].x,t,0); for(int i=2;i<n;i++){ sort(v[i].begin(),v[i].end(),cmp); for(int j=1;j<v[i].size();j++){ insert(v[i][j-1].x,v[i][j].x,v[i][j].v-v[i][j-1].v); insert(v[i][j].x,v[i][j-1].x,0); } } dijk();printf("%lld\n",d[t]); return 0; }
2018.12.30-dtoj-2659-Tax