题目
题目链接:https://www.luogu.com.cn/problem/P5068
珂朵莉给你一个无向图,每次查询的时候给一堆二元组
(
x
i
,
y
i
)
(x_i,y_i)
(xi,yi)
求图中有多少个点
u
u
u与至少一个这次询问给出的二元组
(
x
i
,
y
i
)
(x_i,y_i)
(xi,yi)满足
d
i
s
t
(
u
,
x
i
)
≤
y
i
dist(u,x_i)\leq yi
dist(u,xi)≤yi,
d
i
s
t
dist
dist表示这两个点在图中的距离
如果不连通
d
i
s
t
=
i
n
f
dist = inf
dist=inf
思路:
第一次写出来
Y
n
o
i
Ynoi
Ynoi的题。虽然这是Ynoi为数不多的良心题(雾
设
p
[
i
]
[
j
]
p[i][j]
p[i][j]表示距离点
i
i
i最短路长度不超过
j
j
j的节点集合,那么我们只要求出长度等于
j
j
j的节点集合,然后或上
p
[
i
]
[
j
−
1
]
p[i][j-1]
p[i][j−1]即可。
对于每一个点进行一次
b
f
s
bfs
bfs即可求出
p
p
p。
然后对于每一次询问,其实答案节点集合就是
p
[
x
1
]
[
y
1
]
o
r
p
[
x
2
]
[
y
2
]
o
r
.
.
.
o
r
p
[
x
t
]
[
y
t
]
p[x_1][y_1]\ or\ p[x_2][y_2]\ or\ ...\ or\ p[x_t][y_t]
p[x1][y1] or p[x2][y2] or ... or p[xt][yt]。
p
p
p的类型是
c
+
+
c++
c++自带的
b
i
t
s
e
t
bitset
bitset。每一位只能是0或1,占用空间
1
b
1b
1b。
时间复杂度玄学。
还有洛谷讨论区中说这道题似乎卡邻接表。。。用
v
e
c
t
o
r
vector
vector存边即可。
代码:
#include <queue>
#include <vector>
#include <cstdio>
#include <bitset>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=1010,M=100010,Inf=1e9;
int n,m,Q,x,y,t,tot,dis[N];
bitset<N> p[N][N];
vector<int> e[N];
inline int read()
{
int d=0; char ch=getchar();
while (ch<'0' || ch>'9') ch=getchar();
while (ch>='0' && ch<='9')
d=(d<<3)+(d<<1)+ch-48,ch=getchar();
return d;
}
inline void bfs(int S)
{
memset(dis,0x3f3f3f3f,sizeof(dis));
queue<int> q;
q.push(S); dis[S]=0; p[S][0][S]=1;
while (q.size())
{
int u=q.front();
q.pop();
for (register int i=0;i<e[u].size();i++)
{
int v=e[u][i];
if (dis[v]>Inf)
{
dis[v]=dis[u]+1;
p[S][dis[v]][v]=1;
q.push(v);
}
}
}
for (register int i=1;i<N;i++)
p[S][i]|=p[S][i-1];
}
signed main()
{
n=read(); m=read(); Q=read();
for (register int i=1;i<=m;i++)
{
x=read(); y=read();
e[x].push_back(y);
e[y].push_back(x);
}
for (register int i=1;i<=n;i++)
bfs(i);
while (Q--)
{
t=read();
bitset<N> ans(0);
while (t--)
{
x=read(); y=read();
ans|=p[x][y];
}
printf("%d\n",ans.count());
}
return 0;
}