• 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
    ",ans);
      return 0;
    }
  • 相关阅读:
    [转] 接触C# 反射 2
    [转] C#操作Excel文件
    【Leetcode】Path Sum II
    java通用抹去魔,在边界行动,擦除补偿
    python抓取网络内容
    一个合格的程序猿编程
    Android的相关的源代码的方法
    随笔
    使用方便git命令检查记录的版本号
    opengl 扳回一球
  • 原文地址:https://www.cnblogs.com/Narh/p/9795973.html
Copyright © 2020-2023  润新知