题目
最近,C国成功地渗透进入了D国的一个城市。这个城市可以抽象成一张有n(n≤1000)个节点,节点之间有m条双向道路连接的无向图,每条道路的⻓度都为1。 经过侦查,C国情报部部⻓GGB惊讶地发现,这座看起来不起眼的城市竟然是D国的军事 中心。因此GGB决定在这个城市内设立情报机构。情报专家TAC在侦查后,安排了q 种设立 情报机构的方案。这些方案中,第i种方案将计划建立ki 个情报机构,第j个情报机构可以安排 人员到距离其不超过di,j 的节点上收集情报。 但是,由于人手不足,GGB只能安排上述q种方案中的一种进行实施。为了评估一种方案的 性能,我们把能够收集到情报的节点数量视为这种情报的价值。现在,小∞ ⇔被GGB和TAC派 来侦查,请你帮他统计每一种方案的价值。
题解
一种最朴素的暴力做法,
每次询问都向外扩散,统计有多少个点。
不过可以发现,在这个过程之中,是有非常多重复的操作的,
这样大大减少了时间效率。
考虑如何存下来,
设
f
i
,
k
,
x
f{i,k,x}
fi,k,x表示从第i个点出发,向外走k步,能否到达点x。
首先先预处理f数组,
然后每次询问的时候调用。
分析一下复杂度,预处理f数组要先枚举一个起点,然后遍历完所有的边于是这一部分就是O(nm)的。
对于询问,就是输入的每个点都有枚举一下所有的点,看看是否能够走到,这一部分就是O(n
∑
\sum
∑k)的。
其实,f数组可以bitset实现的,这样又可以除上一个32。
code
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <bitset>
#define N 1003
#define P putchar
#define G getchar
using namespace std;
char ch;
void read(int &n)
{
n=0;
ch=G();
while((ch<'0' || ch>'9') && ch!='-')ch=G();
int w=1;
if(ch=='-')w=-1,ch=G();
while('0'<=ch && ch<='9')n=(n<<3)+(n<<1)+ch-'0',ch=G();
n*=w;
}
void write(int x){if(x>9) write(x/10);P(x%10+'0');}
int n,m,q,x,y,tot,a[N][N],l[N];
int d[N],head,tail,k,dis[N];
bool bz[N][N];
bitset<N> ans,f[N][N];
void work(int st)
{
memset(dis,127,sizeof(dis));
for(dis[d[tail=1]=st]=0,head=0;head<tail;)
{
x=d[++head];y=dis[x];
for(int i=1;i<=l[x];i++)
if(dis[a[x][i]]>n)dis[d[++tail]=a[x][i]]=y+1;
}
for(int i=1;i<=n;i++)if(dis[i]<n)f[st][dis[i]][i]=1;
for(int i=1;i<=n;i++)f[st][i]=f[st][i]|f[st][i-1];
}
int main()
{
freopen("center.in","r",stdin);
freopen("center.out","w",stdout);
read(n);read(m);read(q);
for(int i=1;i<=m;i++)
read(x),read(y),bz[x][y]=bz[y][x]=1;
for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)if(bz[i][j])a[i][++l[i]]=j;
for(int i=1;i<=n;i++)work(i);
for(int i=1;i<=q;i++)
{
read(k);ans.reset();
for(int i=1;i<=k;i++)read(x),read(y),ans=ans|f[x][y];
write(ans.count());P('\n');
}
return 0;
}