码迷,mamicode.com
首页 > 其他好文 > 详细

Luogu P5304 [GXOI/GZOI2019]旅行者

时间:2020-06-06 11:19:28      阅读:47      评论:0      收藏:0      [点我收藏+]

标签:ring   inf   min   编号   ret   状态   --   ==   ++   

Link
二进制分组。每次选定一个二进制位,把特殊点按编号在这一位上的状态分为两半,跑两遍dij求出这两半之间的最短路。

#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
#include<functional>
using i64=long long;
using pi=std::pair<int,int>;
const int N=100007;const i64 inf=1ll<<60;
char ibuf[1<<25],*iS=ibuf;int n,is[N];i64 ans,dis[N];std::vector<pi>e[N];std::priority_queue<pi,std::vector<pi>,std::greater<pi>>q;
int read(){int x=0;while(isspace(*iS))++iS;while(isdigit(*iS))(x*=10)+=*iS++&15;return x;}
void solve(int d,int t)
{
    memset(dis+1,0x3f,8*n);
    for(int i=1;i<=n;++i) if(is[i]&&(i>>d&1)==t) q.emplace(dis[i]=0,i);
    while(!q.empty())
    {
	int u=q.top().second;i64 d=q.top().first;q.pop();
	if(d==dis[u]) for(auto[v,w]:e[u]) if(dis[v]>dis[u]+w) q.emplace(dis[v]=dis[u]+w,v);
    }
    for(int i=1;i<=n;++i) if(is[i]&&(~i>>d&1)==t) ans=std::min(ans,dis[i]);
}
void solve()
{
    n=read(),ans=inf,memset(is+1,0,4*n);
    int m=read(),k=read();
    for(int i=1;i<=n;++i) e[i].clear();
    for(int u,v,w;m;--m) u=read(),v=read(),w=read(),e[u].emplace_back(v,w);
    while(k--) is[read()]=1;
    for(int k=0;k<17;++k) solve(k,0),solve(k,1);
    printf("%lld\n",ans);
}
int main()
{
    fread(ibuf,1,1<<25,stdin);
    for(int t=read();t;--t) solve();
}

Luogu P5304 [GXOI/GZOI2019]旅行者

标签:ring   inf   min   编号   ret   状态   --   ==   ++   

原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/13053653.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!