bzoj 4289 PA2012 Tax——构图

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4289

可以把一个点上的边按权值排序,然后边权小的向第一个比它大的连差值的边,边权大的向第一个比它小的连0边;这样能体现出“边权较大的边的边权”。

别忘了每条边还要自己跟自己连自己权值的边,表示不是差值的初始值。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#define ll long long
using namespace std;
const int N=1e5+5,M=2e5+5;
int n,m,hd[M<<1],xnt,to[M<<3],nxt[M<<3],w[M<<3];
ll dis[M<<1],ans=0x3f3f3f3f3f3f3f3f;//M<<1!v
bool vis[M<<1];
struct Node{
  int bh,w;Node(int a=0,int b=0):bh(a),w(b) {}
};
vector<Node>e[N];
priority_queue<pair<ll,int> > q;
bool cmp(Node u,Node v){return u.w<v.w;}
int rdn()
{
  int ret=0;bool fx=1;char ch=getchar();
  while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();}
  while(ch>='0'&&ch<='9') ret=(ret<<3)+(ret<<1)+ch-'0',ch=getchar();
  return fx?ret:-ret;
}
void add(int x,int y,int z)
{
  to[++xnt]=y;nxt[xnt]=hd[x];hd[x]=xnt;w[xnt]=z;
}
void dj()
{
  while(q.size())
    {
      int k=q.top().second;q.pop();
      if(vis[k])continue; vis[k]=1;
      for(int i=hd[k],v;i;i=nxt[i])
    if(dis[v=to[i]]>dis[k]+w[i])
      {
        dis[v]=dis[k]+w[i];
        q.push(make_pair(-dis[v],v));
      }
    }
}
int main()
{
  n=rdn(); m=rdn();
  for(int i=1,u,v,z;i<=m;i++)
    {
      u=rdn(); v=rdn(); z=rdn(); add(i,i+m,z); add(i+m,i,z);
      e[u].push_back(Node(i,z)); e[v].push_back(Node(i+m,z));
    }
  for(int i=1;i<=n;i++)
    {
      sort(e[i].begin(),e[i].end(),cmp);
      int d=e[i].size();
      for(int j=0;j<d-1;j++)
    {
      add(e[i][j].bh,e[i][j+1].bh,e[i][j+1].w-e[i][j].w);
      add(e[i][j+1].bh,e[i][j].bh,0);
    }
    }
  memset(dis,0x3f,sizeof dis);
  int d=e[1].size();
  for(int i=0;i<d;i++)
    {
      dis[e[1][i].bh]=e[1][i].w;
      q.push(make_pair(-e[1][i].w,e[1][i].bh));
    }
  dj();
  d=e[n].size();
  for(int i=0;i<d;i++)ans=min(ans,dis[e[n][i].bh]);
  printf("%lld\n",ans);
  return 0;
}

 

posted on 2018-10-16 08:59  Narh  阅读(118)  评论(0编辑  收藏  举报

导航