传送门
解析:
一发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;
}