JZOJ 5932. 【NOIP2018模拟10.27】情报中心

本文探讨了在一个给定点数和边数的图中,如何通过SPFA算法结合Bitset进行优化,解决特定路径查询问题。具体地,介绍了如何在O(mq)的时间复杂度下,使用Bitset替代bool数组来统计点的可达性,实现高效的路径搜索和计数。

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

题目

给定一个点数为n个图,m条边。
走一条边算1步。
共有q个询问
每个询问中有k个点,求有多少个点可以走最多v步走到询问中的任意一个点。
数据范围 n &lt; = 1000 , m &lt; = 100000 n&lt;=1000,m&lt;=100000 n<=1000,m<=100000

题解

其他猎奇的方法

一个O(mq)的失败方法:排个序做,每个点有一个状态t,表示点t仍可以走t的时间。
灵感来源于剩余相同的时间点可以一起做(序列中连续一段点的t都是相同的)。

正解

寻址优化。将前向星换成边集数组。
bitset替换统计哪些点是否出现过的bool数组。
spfa,其中不需要松弛。

反思

没拍,比赛快结束的时候发现有错,赶紧调,结果没有发现完所有的sb错误。
bitset操作:大佬的博客请点此处

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<bitset>
#include<algorithm>
#define N 1005
#define P(a) putchar(a)
using namespace std;
int i,j,k,l,n,m,q;
int cx[N],map[N][N];
int u,v,qu[N],dis[N];
bool Bz[N][N];
bitset<N>d[N][N],ans;
int read(){
	int fh=0,rs=0;char ch=0;
	while((ch<'0'||ch>'9')&&(ch^'-'))ch=getchar();
	if(ch=='-')fh=1,ch=getchar();
	while(ch>='0'&&ch<='9')rs=(rs<<3)+(rs<<1)+(ch^'0'),ch=getchar();
	return fh?-rs:rs;
}
void write(int x){
	if(x>9)write(x/10);
	P(x%10+'0');
}
int main(){
	freopen("center.in","r",stdin);
	freopen("center.out","w",stdout);
	n=read(),m=read(),q=read();
	for(i=1;i<=m;i++)u=read(),v=read(),(!Bz[u][v]?Bz[u][v]=Bz[v][u]=1,map[u][++cx[u]]=v,map[v][++cx[v]]=u:0);
	for(u=1;u<=n;u++){
		for(i=1;i<=n;i++)dis[i]=2139062143;
		dis[u]=0;
		qu[l=1]=u;
		for(i=1;i<=l;i++){
			v=qu[i];
			for(j=1;j<=cx[v];j++)(dis[map[v][j]]>dis[v]+1?dis[map[v][j]]=dis[v]+1,qu[++l]=map[v][j]:0);
		}
		for(i=1;i<=n;i++)(dis[i]<2139062143?d[u][dis[i]][i]=1:0);
		for(i=1;i<=n;i++)d[u][i]|=d[u][i-1];
	}
	while(q--){
		k=read();ans.reset();
		while(k--){
			u=read(),v=read();
			ans|=d[u][v];
		}
		write(ans.count()),P('\n');
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值