[USACO24FEB] Bessla Motors G 题解

题目大意

对于每个充电站找它所能去到的非充电站的点 T T T($ C<T$ 同时两点的距离在 R R R 之内)。
然后对点 T T T进行统计,看共有多少不同的充电站经过它(设达成条件的充电站个数为 x x x)。

对于每个 x x x

如果有 K ≤ x K\leq x Kx 则该点被计入答案

分析

这道题直接跑全源最短路( J o h n s o n Johnson Johnson)。
J o h n s o n Johnson Johnson 的时间复杂度为 O ( N M log ⁡ M ) O(NM\log M) O(NMlogM)

分两类,从充电站跑和从非充电站跑。

由于数据很水所以卡一下数据就能过。

Code

#include<bits/stdc++.h>
using namespace std;
const int MAXN=5e4+100;
const int MAXM=1e5+100;
const int inf=2147483647;
int n,m,c,r,k,cnt,sum,d[MAXN],hd[MAXM*2],nxt[MAXM*2],to[MAXM*2],val[MAXM*2],bz[MAXN];
bool vis[MAXN];
inline void myswap(int &x,int &y){int t=x;x=y;y=t;}
inline void add(int u,int v,int l)
{
	to[++cnt]=v;
	val[cnt]=l;
	nxt[cnt]=hd[u];
	hd[u]=cnt;
}
struct heap
{
	int q[MAXN],id[MAXN],len;
	inline void init(){len=0;}
	inline void push(int x,int iid)
	{
		len++;
		q[len]=x;
		id[len]=iid;
		int p=len;
		while(p/2&&q[p/2]>q[p])
		{
			myswap(q[p/2],q[p]);
			myswap(id[p/2],id[p]);
			p/=2;
		}
	}
	inline int getmin(){return id[1];}
	inline void pop()
	{
		id[1]=id[len];
		q[1]=q[len--];
		int p=1;
		while(p*2<=len)
		{
			int son=p*2;
			if(son+1<=len&&q[son+1]<q[son]) son++;
			if(q[p]<q[son]) break;
			myswap(q[son],q[p]);
			myswap(id[son],id[p]);
			p=son;
		}
	}
	inline bool empty(){return len>0?false:true;}
}hp;
inline void Dijkstra(int s)
{
	hp.init();
	int res=inf;
	for(int i=1;i<=n;i++) d[i]=inf,vis[i]=false;
	hp.push(0,s);
	d[s]=0;
	while(!hp.empty())
	{
		int x=hp.getmin();
		hp.pop();
		if(vis[x]) continue ;
		if(!vis[x]&&x>c)
		{
			bz[x]++;
			if(bz[x]==k) sum++;
		}
		vis[x]=true;
		for(int i=hd[x];i;i=nxt[i])
		{
			int v=to[i],l=val[i];
			if(d[v]>d[x]+l&&d[x]+l<=r)
			{
				d[v]=d[x]+l;
				if(!vis[v]) hp.push(d[v],v);
			}
		}
	}
}
inline void Dijkstra2(int s)
{
	hp.init();
	int res=inf;
	for(int i=1;i<=n;i++) d[i]=inf,vis[i]=false;
	hp.push(0,s);
	d[s]=0;
	while(!hp.empty())
	{
		int x=hp.getmin();
		hp.pop();
		if(vis[x]) continue ;
		vis[x]=true;
		for(int i=hd[x];i;i=nxt[i])
		{
			int v=to[i],l=val[i];
			if(d[v]>d[x]+l&&d[x]+l<=r)
			{
				d[v]=d[x]+l;
				if(v<=c) bz[s]++;
				if(bz[s]==k)
				{
					sum++;
					break;
				}
				if(!vis[v]) hp.push(d[v],v);
			}
		}
		if(bz[s]==k) break;
	}
}
int main()
{
//	freopen("bm.in","r",stdin);
//	freopen("bm.out","w",stdout);
	scanf("%d%d%d%d%d",&n,&m,&c,&r,&k);
	for(int i=1;i<=m;i++)
	{
		int u,v,l;
		scanf("%d%d%d",&u,&v,&l);
		add(u,v,l),add(v,u,l);
	}
	if(c<=10000) for(int i=1;i<=c;i++)
	{
		Dijkstra(i);
	}
	else for(int i=c+1;i<=n;i++)
	{
		Dijkstra2(i);
	}
	printf("%d\n",sum);
	for(int i=c+1;i<=n;i++) if(bz[i]>=k) printf("%d\n",i);
	return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值