[ZROJ-961]路径长度 Solution

本文探讨了在有向无环图中优化路径查询算法的方法,特别是在路径长度限制下,通过智能存储和拓扑排序来减少不必要的计算,从而提高效率。文章详细介绍了如何避免重复计算和无效节点存储,提出了一种有效的合并策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

给你一个有向无环图,QQQ次询问,每次问111kkk是否有一条路径长度sss满足k≤s≤1.1×kk\leq s\leq1.1\times kks1.1×k
如果直接暴力背包,是得不到满分的,好像空间也存不下,考虑如何优化?哪些点存下来是没有必要的呢?考虑这种情况:11.1x≤y≤x\frac{1}{1.1}x\leq y\leq x1.11xyx,这种情况下yyy是没有存在的必要的。所以我们不必存它。
所以就可以直接拓扑,然后归并答案,对于每个询问直接暴力扫也是可以的。因为按照上述方法存点差不多每个点只会存400400400个值。
code:code:code:

#include <bits/stdc++.h>
#define int long long
#define regi register int
int n,m,q;
int in[200001];
long long f[200001][401];
int Tot[200001];
int head[500001],tot;
long long temp[200001];
std::queue<int>Q;
struct edge{
	int to;
	int nxt;
	int w;
}e[1000001];
inline int read(){
    int r=0,w=0,c;
    for(;!isdigit(c=getchar());r=c);
    for(w=c^48;isdigit(c=getchar());w=w*10+(c^48));
    return r^45?w:-w;
}
inline void add(int x,int y,int z){
	e[++tot]={y,head[x],z};head[x]=tot;
}
inline long long calc(long long x){
	return x*11/10;
}
inline void merge(int x,int y,int z){
	if(!Tot[x]&&!Tot[y])
	  return;
  regi i=1,j=1,tail=0;
	while(i<=Tot[x]&&j<=Tot[y])
	  if(f[x][i]+z<=f[y][j])
		  temp[++tail]=f[x][i++]+z;
		else
		  temp[++tail]=f[y][j++];
	while(i<=Tot[x])
	  temp[++tail]=f[x][i++]+z;
	while(j<=Tot[y])
	  temp[++tail]=f[y][j++];
  f[y][Tot[y]=1]=temp[1];
  f[y][0]=0;
  for(regi i=2;i<=tail;++i)
    if(temp[i]<=calc(f[y][Tot[y]-1]))
      f[y][Tot[y]]=temp[i];
    else
      f[y][++Tot[y]]=temp[i];
}
main(){
	n=read(),m=read(),q=read();
	for(regi i=1,x,y,z;i<=m;++i){
		x=read(),y=read(),z=read();
		add(x,y,z);
		in[y]++;
	}
	Tot[1]=1;
	f[1][1]=0;
	for(regi i=1;i<=n;++i)
	  if(!in[i])
	    Q.push(i);
	while(!Q.empty()){
		regi x=Q.front();
		Q.pop();
		for(regi i=head[x];i;i=e[i].nxt){
			regi y=e[i].to;
			regi z=e[i].w;
			merge(x,y,z);
			if(!--in[y])
			  Q.push(y);
		}
	}
	while(q--){
		regi x=read(),y=read();
		bool flag=0;
		for(regi i=1;i<=Tot[x];++i)
		  flag|=(y<=f[x][i]&&calc(y)>=f[x][i]);
		flag?puts("YES"):puts("NO");
	}
  return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值