1. 程式人生 > >JZOJ 5932. 【NOIP2018模擬10.27】情報中心

JZOJ 5932. 【NOIP2018模擬10.27】情報中心

題目

給定一個點數為n個圖,m條邊。
走一條邊算1步。
共有q個詢問
每個詢問中有k個點,求有多少個點可以走最多v步走到詢問中的任意一個點。
資料範圍 n < = 1000 , m <

= 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; }