Newcoder 82 E.无向图中的最短距离(bfs+bitset)

186 篇文章 0 订阅
125 篇文章 0 订阅

Description

有一个 n n n个点的无向图,有 m m m次查询,每次查询给出一些 ( x i , y i ) (x_i,y_i) (xi,yi)

d i s t ( x , y ) dist(x,y) dist(x,y)表示 x x x y y y点在图中最短距离, d i s t ( x , x ) = 0 dist(x,x)=0 dist(x,x)=0,如果 x , y x,y x,y不连通则 d i s t ( x , y ) = i n f dist(x,y) = inf dist(x,y)=inf

每次查询图中有多少个点 v v v与至少一个这次询问给出的 ( x i , y i ) (x_i,y_i) (xi,yi)满足 d i s t ( v , x i ) ≤ y i dist(v,x_i)\le y_i dist(v,xi)yi

Input

第一行三个数表示 n , m , q n,m,q n,m,q

之后 m m m行每行两个数 x , y x,y x,y表示有一条 x x x y y y之间的边,边权为 1 1 1

之后 q q q次询问,每个询问先给你一个数 a a a

之后一行 2 a 2a 2a个数,第 2 i − 1 2i-1 2i1个数 x i x_i xi和第 2 i 2i 2i个数 y i y_i yi表示一个二元组 ( x i , y i ) (x_i,y_i) (xi,yi)

( n ≤ 1 0 3 , m ≤ 1 0 5 , q ≤ 1 0 5 , ∑ ∣ a ∣ ≤ 2100000 ) (n\le 10^3,m\le 10^5,q\le 10^5,\sum |a|\le 2100000) (n103,m105,q105,a2100000)

Output

输出 q q q行,每行一个数表示这次询问的答案

Sample Input

5 6 6
2 3
1 3
2 5
1 3
3 2
2 5
1
3 1
1
1 1
1
1 4
1
5 2
1
1 4
2
1 0 5 1

Sample Output

3
2
4
3
4
3

Solution

从每点开始 b f s bfs bfs,用 f [ i ] [ j ] f[i][j] f[i][j]这个 b i t s e t bitset bitset记录所有与 i i i点距离不超过 j j j的点,那么对于一组查询,把所有 f [ x i ] [ y i ] f[x_i][y_i] f[xi][yi]或一下统计 1 1 1的个数即可,时间复杂度 O ( n 3 32 ) O(\frac{n^3}{32}) O(32n3)

Code

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<ctime>
#include<bitset>
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
const int INF=0x3f3f3f3f,maxn=1005;
bitset<1005>f[maxn][maxn],ans;
int n,m,q,dis[maxn];
vector<int>g[maxn];
void bfs(int s)
{
	queue<int>que;
	que.push(s);
	f[s][0].set(s);
	memset(dis,-1,sizeof(dis));
	dis[s]=0;
	while(!que.empty())
	{
		int u=que.front();que.pop();
		for(int i=0;i<g[u].size();i++)
		{
			int v=g[u][i];
			if(dis[v]!=-1)continue;
			dis[v]=dis[u]+1;
			que.push(v);
			f[s][dis[v]].set(v);
		}
	}
	for(int i=1;i<=n;i++)f[s][i]|=f[s][i-1];
}
int main()
{
	scanf("%d%d%d",&n,&m,&q);
	while(m--)
	{
		int u,v;
		scanf("%d%d",&u,&v);
		g[u].push_back(v),g[v].push_back(u);
	}
	for(int i=1;i<=n;i++)bfs(i);
	while(q--)
	{
		int a,x,y;
		scanf("%d",&a);
		ans.reset();
		while(a--)
		{
			scanf("%d%d",&x,&y);
			y=min(y,n);
			ans|=f[x][y];
		}
		printf("%d\n",ans.count());
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值