BZOJ 4289: PA2012 Tax 差分建图 最短路
https://www.lydsy.com/JudgeOnline/problem.php?id=4289
https://www.cnblogs.com/clrs97/p/5046933.html claris的题解很清晰
如果单纯把无向边拆成有向边然后变成点再连有向边需要建m^2条边。
那么这里可以差分建图压缩新图边的数量,把原图每个点的出边和入边排序,权值相同的出边到入边(开始是无向图所以每个出边一定有权值相同的入边,入边也是)连一条权值为相同权值的边。
(从小到大排序后)每条出边往它的前一条边连一条权值为0的边,向后一条边连一条权值为 (后一条边权值)-(当前边权值) 的边。
最后设置一个总入点和总出点相应连1的出边和n的入边就可以了。
合理性就不再说了。
空间要注意,这道题空间开小了wa开大了tle。卡了半天......
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #include<cmath> 6 #include<queue> 7 using namespace std; 8 #define LL long long 9 #define pa pair<LL,int> 10 const int maxn=210000; 11 int n,m; 12 struct node{ int x,y;LL v; }a[maxn*2],b[maxn*2];int cnt=0; 13 struct nod1{ int y,z,next; }e1[maxn*2]; 14 struct nod{ int y,next;LL v;}e[maxn*10]; 15 int head1[maxn]={},head[maxn*2]={},tot1=0,tot=0; 16 priority_queue< pa ,vector< pa > , greater< pa > >q; 17 int S,T; LL dis[maxn*2]={}; 18 inline void init1(int x,int y,int z){e1[++tot1].y=y;e1[tot1].z=z;e1[tot1].next=head1[x];head1[x]=tot1;} 19 inline void init(int x,int y,LL v){e[++tot].y=y;e[tot].v=v;e[tot].next=head[x];head[x]=tot;} 20 bool mcmp(node aa,node bb){return aa.v<bb.v;} 21 void Dij(){ 22 memset(dis,63,sizeof(dis)); 23 dis[S]=0;q.push(make_pair(dis[S],S)); 24 while(!q.empty()){ 25 LL v=q.top().first;int x=q.top().second;q.pop(); 26 if(v>dis[x])continue; 27 for(int i=head[x];i;i=e[i].next){ 28 if(dis[e[i].y]>dis[x]+e[i].v){ 29 dis[e[i].y]=dis[x]+e[i].v; 30 q.push(make_pair(dis[e[i].y],e[i].y)); 31 } 32 } 33 } 34 } 35 int main(){ 36 scanf("%d%d",&n,&m); 37 int x,y;LL z; 38 for(int i=1;i<=m;i++){ 39 scanf("%d%d%lld",&x,&y,&z); 40 a[++cnt].x=x;a[cnt].y=y;a[cnt].v=z; 41 a[++cnt].x=y;a[cnt].y=x;a[cnt].v=z; 42 init1(x,cnt,cnt-1);init1(y,cnt-1,cnt);//入边 出边 43 } 44 S=cnt+1;T=S+1; 45 for(int i=1;i<=n;i++){ 46 int zz=0; 47 for(int j=head1[i];j;j=e1[j].next){ 48 b[++zz].x=e1[j].y; b[zz].y=e1[j].z; b[zz].v=a[e1[j].y].v; 49 } 50 sort(b+1,b+1+zz,mcmp); 51 for(int j=1;j<=zz;j++)init(b[j].x,b[j].y,b[j].v); 52 for(int j=1;j<zz;j++){init(b[j+1].y,b[j].y,0); init(b[j].y,b[j+1].y,b[j+1].v-b[j].v);} 53 } 54 for(int i=1;i<=cnt;i++){ 55 if(a[i].y==n)init(i,T,a[i].v); 56 if(a[i].x==1)init(S,i,a[i].v); 57 } 58 Dij(); 59 printf("%lld\n",dis[T]); 60 return 0; 61 }