JZOJ 5932. 【NOIP2018模擬10.27】情報中心
阿新 • • 發佈:2018-11-01
題目
給定一個點數為n個圖,m條邊。
走一條邊算1步。
共有q個詢問
每個詢問中有k個點,求有多少個點可以走最多v步走到詢問中的任意一個點。
資料範圍
題解
其他獵奇的方法
一個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;
}