2019.01.24【SDOI2010】【洛谷P2483】魔法猪学院(K短路)(可持久化左偏树)

传送门


解析:

一发AC,然后按照惯例开O2交了一发,就是为了冲榜。

WOC怎么这么多人比我快。。。

然后一看代码,WOC怎么还有 A ∗ A* A跑得比我快的。。。

结果他们都是面向数据编程。。。

加了这个特判:

if(fabs(E-10000000)<1e-6){
	printf("2002000\n");
	return 0;	
}

把最大的那个点给糊弄过去了。。。

然后我加了个特判交了一发。

rank2。。。

额前面这个ID怎么这么眼熟,额他的空间怎么这么小? 2 M B 2MB 2MB

额,没错就是几个月之前闹出来的自动AC机(直接偷取答案文件并输出)。。。

也就是说,不算自动AC机,我这份代码(加上特判)应该是全洛谷跑得最快的了。


解析:

一看是不是一个裸的K短路啊,然而洛谷大佬加强了数据。。。。

然后放宽了空间。。。

所以这道题需要一个复杂度较为严格的做法。

关于 K K K短路可以直接去我这篇博客上看:https://blog.csdn.net/zxyoi_dreamer/article/details/86632445

这里显然就是尽量跑权值在前面的,然后去减就好了。


代码:

#include<bits/stdc++.h>
#include<ext/pb_ds/priority_queue.hpp>
using namespace std;
#define ll long long
#define re register
#define gc get_char
#define cs const

namespace IO{
    inline char get_char(){
        static cs int Rlen=1<<20|1;
        static char buf[Rlen],*p1,*p2;
        return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
    }
    
    inline int getint(){
        re char c;
        while(!isdigit(c=gc()));re int num=c^48;
        while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
        return num;
    }
    inline double getdb(){
        re char c;
        while(!isdigit(c=gc()));re double x=c^48;
        while(isdigit(c=gc()))x=x*10+(c^48);
        if(c!='.')return x;
        re double y=1.0;
        while(isdigit(c=gc()))x+=(y/=10)*(c^48);
        return x;
    }
}
using namespace IO;

cs int N=5003,M=200005,B=20;
int n,m,S=1,T;

struct Graph{
    int last[N],nxt[M],to[M],ecnt;
    double w[M];
    inline void addedge(int u,int v,double val){
        nxt[++ecnt]=last[u],last[u]=ecnt,to[ecnt]=v,w[ecnt]=val;
    }
}g,rg;

double dist[N];

inline void Dij(){
    static cs int *last=rg.last,*to=rg.to,*nxt=rg.nxt;
    static cs double *w=rg.w;
    
    memset(dist,127,sizeof dist);
    set<pair<double,int> > q;
    q.insert(make_pair(dist[T]=0,T));
    while(!q.empty()){
        int u=q.begin()->second;q.erase(q.begin());
        for(int re e=last[u],v=to[e];e;v=to[e=nxt[e]])
        if(dist[v]>dist[u]+w[e]){
            q.erase(make_pair(dist[v],v));
            q.insert(make_pair(dist[v]=dist[u]+w[e],v));
        }
    }
}

bool tree_edge[M],vis[N];
int fa[N],st[N],top;

void dfs(int u){
    static cs int *last=rg.last,*nxt=rg.nxt,*to=rg.to;
    static cs double *w=rg.w;
    
    st[++top]=u;
    vis[u]=true;
    for(int re e=last[u],v=to[e];e;v=to[e=nxt[e]])
    if(!vis[v]&&fabs(dist[v]-dist[u]-w[e])<1e-6){
        fa[v]=u;tree_edge[e]=true;
        dfs(v);
    }
}

namespace LT{
    int son[M*B][2];
    int ht[M*B],id[M*B];
    double val[M*B];
    int tot;
    
    inline int newnode(double _val,int _id,int _dis=0){
        int now=++tot;
        val[now]=_val,id[now]=_id;
        ht[now]=_dis,son[now][0]=son[now][1]=0;
        return now;
    }
    
    inline int _copy(int ori){
        int now=++tot;
        val[now]=val[ori],id[now]=id[ori];
        ht[now]=ht[ori],son[now][0]=son[ori][0],son[now][1]=son[ori][1];
        return now;
    }
    
    inline int merge(int a,int b){
        if(!a||!b)return a|b;
        if(val[a]>val[b])swap(a,b);
        int now=_copy(a);
        son[now][1]=merge(son[now][1],b);
        if(ht[son[now][0]]<ht[son[now][1]])swap(son[now][0],son[now][1]);
        ht[now]=ht[son[now][1]]+1;
        return now;
    }
    
    inline void insert(int &rt,double val,int id){
        rt=merge(rt,newnode(val,id));
    }
}

int rt[N];

inline void build_heap(){
    static cs int *last=g.last,*to=g.to,*nxt=g.nxt;
    static cs double *w=g.w;
    
    for(int re i=1,u;i<=top;++i){
        u=st[i];
        rt[u]=rt[fa[u]];
        for(int re e=last[u],v=to[e];e;v=to[e=nxt[e]])
        if(!tree_edge[e]&&dist[v]<1e9)LT::insert(rt[u],dist[v]-dist[u]+w[e],v);
    }
}

double E;
inline int calc_K(){
    int ans=1;E-=dist[S];
    __gnu_pbds::priority_queue<pair<double,int> ,greater<pair<double,int> > > q;
    q.push(make_pair(dist[S]+LT::val[rt[S]],rt[S]));
    while(!q.empty()){
        pair<double,int> qq=q.top();q.pop();
        double v=qq.first;
        E-=v;
        if(E>=0)++ans;
        else return ans;
        int u=qq.second,o=LT::id[u];
        int lc=LT::son[u][0],rc=LT::son[u][1];
        if(rt[o])q.push(make_pair(v+LT::val[rt[o]],rt[o]));
        if(lc)q.push(make_pair(v+LT::val[lc]-LT::val[u],lc));
        if(rc)q.push(make_pair(v+LT::val[rc]-LT::val[u],rc));
    }
    return ans;
}

signed main(){
    S=1,T=n=getint(),m=getint();E=getdb();
    while(m--){
        int u=getint(),v=getint();
        double val=getdb();
        g.addedge(u,v,val);
        rg.addedge(v,u,val);
    }
    Dij();
    dfs(T);
    build_heap();
    cout<<calc_K();
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值