洛谷P5468/LOJ3156[NOI2019]回家路线

只会$O(mt)$

首先这个题有点,有时间,便套路地想到拆点 ~~(或许我网络流做多了)~~ ,设最大时间为$t$,那么把每个点拆成$t$个,连上原图的边和等待即可。

恭喜拿到$70pts$

在这个思(bao)路(li)的基础上,我们发现,每个点拆成$t$个是毫无意义的,只要保留所有进出的时间点就可以了,于是总点数从$nt$下降为$2m$,用$dijkstra$复杂度下降到$O(m(t+logn))$,大约$2 \times 10^8$,轻松跑过一点都不虚233

你们说dij死了我偏要用dij

#include<cstdio>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
typedef long long ll;
const int N=100050;
char rB[1<<21],*S,*T;
inline char gc(){return S==T&&(T=(S=rB)+fread(rB,1,1<<21,stdin),S==T)?EOF:*S++;}
inline int rd(){
    char c=gc();
    while(c<48||c>57)c=gc();
    int x=c&15;
    for(c=gc();c>=48&&c<=57;c=gc())x=(x<<3)+(x<<1)+(c&15);
    return x;
}
int G[N],p[N<<1],q[N<<1],to[N<<1],nxt[N<<1],n,m,A,B,C;
struct node{
    int p,t;
    ll d;
    bool go;  //上一步是坐车则为1,等待则为0
    node(){}
    node(int p,int t,ll d,bool go):p(p),t(t),d(d),go(go){}
    inline bool operator <(const node &b)const{return d>b.d;}
};
priority_queue<node> Q;
vector<int> tim[N],tmp;  //tim对时刻离散化
vector<vector<int> > id[N];  //记录u结点t时刻出发的边的编号
vector<ll> d[2][N];
int main(){
    int i,u;
    node h;
    ll ans=0x3f3f3f3f3f3f3f3f;
    n=rd();m=rd();A=rd();B=rd();C=rd();
    for(i=1;i<=m;++i){
        u=rd();to[i]=rd();p[i]=rd();q[i]=rd();
        nxt[i]=G[u];G[u]=i;
    }
    tim[1].push_back(0);
    for(u=1;u<=n;++u)
        for(i=G[u];i;i=nxt[i]){
            tim[u].push_back(p[i]);
            tim[to[i]].push_back(q[i]);
        }
    for(u=1;u<=n;++u){
        sort(tim[u].begin(),tim[u].end());
        vector<int>::iterator it=unique(tim[u].begin(),tim[u].end());
        tim[u].erase(it,tim[u].end());  //去重
        for(i=0;i<tim[u].size();++i){
            id[u].push_back(tmp);
            d[0][u].push_back(ans);d[1][u].push_back(ans);
        }
    }
    for(u=1;u<=n;++u)
        for(i=G[u];i;i=nxt[i]){
            id[u][p[i]=lower_bound(tim[u].begin(),tim[u].end(),p[i])-tim[u].begin()].push_back(i);
            q[i]=lower_bound(tim[to[i]].begin(),tim[to[i]].end(),q[i])-tim[to[i]].begin();
        }
    Q.push(node(1,0,d[1][1][0]=0ll,1));
    while(!Q.empty()){
        h=Q.top();Q.pop();
        if(d[h.go][u=h.p][h.t]!=h.d)continue;
        if(h.d>ans)break;  //剪枝
        if(u==n&&h.d+tim[n][h.t]<ans)ans=h.d+tim[n][h.t];
        if(h.go)for(i=h.t;i<tim[u].size();++i)if(h.d+A*(tim[u][i]-tim[u][h.t])*(tim[u][i]-tim[u][h.t])+B*(tim[u][i]-tim[u][h.t])+C<d[0][u][i])Q.push(node(u,i,d[0][u][i]=h.d+A*(tim[u][i]-tim[u][h.t])*(tim[u][i]-tim[u][h.t])+B*(tim[u][i]-tim[u][h.t])+C,0));  //等待
        else;
        else for(i=0;i<id[u][h.t].size();++i)if(h.d<d[1][to[id[u][h.t][i]]][q[id[u][h.t][i]]])Q.push(node(to[id[u][h.t][i]],q[id[u][h.t][i]],d[1][to[id[u][h.t][i]]][q[id[u][h.t][i]]]=h.d,1));  //坐车
    }
    printf("%lld",ans);
    return 0;
}
View Code

猜你喜欢

转载自www.cnblogs.com/sunshine-chen/p/11258763.html