【JZOJ4858】【GDOI2017模拟11.4】Walk

来源:互联网 发布:海龟交易系统源码 编辑:程序博客网 时间:2024/06/06 15:41

题目描述

在比特镇一共有n 个街区,编号依次为1 到n,它们之间通过若干条单向道路连接。
比特镇的交通系统极具特色,除了m 条单向道路之外,每个街区还有一个编码vali,不同街区可能拥有相同的编码。如果val_i and val_j = val_j,即val_i 在二进制下与val_j 做与运算等于val_j,那么也会存在一条额外的从i 出发到j 的单向道路。
Byteasar 现在位于1 号街区,他想知道通过这些道路到达每一个街区最少需要多少时间。因为比特镇的交通十分发达,你可以认为通过每条道路都只需要1 单位时间。

数据范围

这里写图片描述

=w=

暴力连边后做最短路,但这样显然边数太多。
对于一个点i,他可以额外连向j,当且仅当val[i]&val[j]==val[j]。
如果把这条边拆成(i,val[i]),(val[i],val[j]),(val[j],j),那么显然可以使用差分模型优化边数。

代码

#include<iostream>#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>#define ll long long#define sqr(x) ((x)*(x))#define ln(x,y) int(log(x)/log(y))#define point(x) ((x)+maxa-1)using namespace std;const char* fin="walk.in";const char* fout="walk.out";const int inf=0x7fffffff;const int maxn=1548576,maxm=maxn*4,maxa=1<<20;int n,m,i,j,k;int fi[maxn],la[maxm],ne[maxm];int va[maxm];int tot,a[maxn];int head,tail,b[maxn*3],dis[maxn];bool bz[maxn];void add_line(int a,int b,int c){    tot++;    ne[tot]=fi[a];    la[tot]=b;    va[tot]=c;    fi[a]=tot;}void add(int v,int v1){    if (dis[v]>v1){        dis[v]=v1;        if (!bz[v]){            bz[v]=true;            b[++tail]=v;        }    }}void spfa(int v){    int i,j,k;    head=tail=0;    memset(dis,127,sizeof(dis));    add(v,0);    while (head++<tail){        if (b[head]<maxa)            for (i=0;i<20;i++)                if (b[head]&(1<<i)) add(b[head]^(1<<i),dis[b[head]]);        for (k=fi[b[head]];k;k=ne[k]) add(la[k],dis[b[head]]+va[k]);        bz[b[head]]=false;    }}int main(){    freopen(fin,"r",stdin);    freopen(fout,"w",stdout);    scanf("%d%d",&n,&m);    for (i=1;i<=n;i++){        scanf("%d",&k);        add_line(point(i),k,1);        add_line(k,point(i),0);    }    for (i=1;i<=m;i++){        scanf("%d%d",&j,&k);        add_line(point(j),point(k),1);    }    spfa(point(1));    for (i=1;i<=n;i++) if (dis[point(i)]>2000000000) printf("-1\n");    else printf("%d\n",dis[point(i)]);    return 0;}

启发

对于一个相同条件来进行连边的,考虑拆边来达到差分模型优化边数。

0 0