GXOI/GZOI2019 旅行者

Posted fengxunling

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了GXOI/GZOI2019 旅行者相关的知识,希望对你有一定的参考价值。

题目链接:戳我

这是同学出的题,真心神仙qwq

我们进行二进制分组,因为如果答案是\(k_i\)\(k_j\)之间的距离的话,他们的编号必定在某一位上不一样。
所以这样子做是对的。跑dij的次数降低到2*log次。

不过最好还是不要像我一样懒,分组之后重新加边,不加O2会慢死的........

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#define ss 0
#define tt n+1
#define MAXN 100010
#define MAXM 500010
using namespace std;
int n,m,t,T,k,cnt_a,cnt_b;
int head[MAXN],done[MAXN],kkk[MAXN];
long long ans;
long long dis[MAXN];
vector<int>G[MAXN];
struct Node

    int u;
    long long d;
    friend bool operator < (Node x,Node y)
    return x.d>y.d;
;
struct Edgeint nxt,to,dis;edge[MAXM<<1];
struct Lineint x,y,w;line[MAXM];
inline void add(int from,int to,int dis)

    // printf("[%d %d] %d\n",from,to,dis);
    edge[++t].nxt=head[from],edge[t].to=to,edge[t].dis=dis;
    head[from]=t;


inline void dij(int s)

    priority_queue<Node>q;
    for(int i=0;i<=n+1;i++) dis[i]=0x3f3f3f3f,done[i]=0;
    dis[s]=0;
    q.push((Node)s,0);
    while(!q.empty())
    
        int u=q.top().u;q.pop();
        if(done[u]) continue;
        done[u]=1;
        for(int i=head[u];i;i=edge[i].nxt)
        
            int v=edge[i].to;
            if(dis[v]>dis[u]+edge[i].dis)
            
                dis[v]=dis[u]+edge[i].dis;
                q.push((Node)v,dis[v]);
            
        
    

inline void solve_1(int x)

    t=0;
    memset(head,0,sizeof(head));
    for(int i=1;i<=k;i++)
    
        if(kkk[i]&(1<<x)) add(ss,kkk[i],0);
        else add(kkk[i],tt,0);
    
    for(int i=1;i<=m;i++) add(line[i].x,line[i].y,line[i].w);
    dij(ss);
    ans=min(ans,dis[tt]);
    // printf("dis[tt]=%lld\n",dis[tt]);

inline void solve_2(int x)

    t=0;
    memset(head,0,sizeof(head));
    for(int i=1;i<=k;i++)
    
        if(kkk[i]&(1<<x)) add(kkk[i],tt,0);
        else add(ss,kkk[i],0);
    
    for(int i=1;i<=m;i++) add(line[i].x,line[i].y,line[i].w);
    dij(ss);
    ans=min(ans,dis[tt]);
    // printf("dis[tt]=%lld\n",dis[tt]);

int main()

    #ifndef ONLINE_JUDGE
    freopen("ce.in","r",stdin);
    #endif
    scanf("%d",&T);
    while(T--)
    
        scanf("%d%d%d",&n,&m,&k);
        for(int i=1;i<=m;i++)
            scanf("%d%d%d",&line[i],&line[i].y,&line[i].w);
        for(int i=1;i<=k;i++) scanf("%d",&kkk[i]);
        ans=0x3f3f3f3f3f3f3f3f;
        for(int i=0;i<=17;i++)
        
            solve_1(i);
            solve_2(i);
            // puts("");
        
        printf("%lld\n",ans);
    
    return 0;

以上是关于GXOI/GZOI2019 旅行者的主要内容,如果未能解决你的问题,请参考以下文章

[GXOI/GZOI2019]旅行者

题解:[GXOI/GZOI2019]旅行者

Luogu P5304 [GXOI/GZOI2019]旅行者

Luogu P5304 [GXOI/GZOI2019]旅行者

Luogu P5304 [GXOI/GZOI2019]旅行者

[LuoguP5305][GXOI/GZOI2019]旧词 (树链剖分)