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

Description

題目背景
。飛紛火戰來年近國 D 和國 C
。飛亂子鴿來年近國 D 和國 C
題面描述
最近,C 國成功地滲透進入了 D 國的一個城市。這個城市可以抽象成一張有 n 個節點,節點之間有 m 條雙向道路連接的無向圖,每條道路的⻓度都爲 1 。
經過偵查,C 國情報部部⻓ GGB 驚訝地發現,這座看起來不起眼的城市竟然是 D 國的軍事中心。因此 GGB 決定在這個城市內設立情報機構。情報專家 TAC 在偵查後,安排了 q 種設立情報機構的方案。這些方案中,第 i 種方案將計劃建立 ki 個情報機構,第 j 個情報機構可以安排人員到距離其不超過 di,j 的節點上收集情報。
Description

Input

從文件 center.in 中讀入數據。
   輸入第一行包含三個正整數 n, m, q ,分別表示城市的節點個數、道路條數和方案個數。
  接下去 m 行每行兩個正整數 u, v ,表示存在一條連接城市 u 和城市 v 的雙向道路。
  接下去 q 行,每行表示一個方案。第一個正整數 k 表示該種方案將計劃建立 k 個情報機構,之後是 2k 個正整數,其中第 2i − 1 個數表示方案中第 i 個情報機構所在的節點編號,第 2i 個數表示第 i 個情報點所能派出情報人員的最遠距離。

Output

輸出到文件 center.out 中。
輸出包含 q 行,每行包含一個整數,表示相應詢問的答案。

Sample Input

5 8 3
1 2
1 3
1 4
1 5
2 4
2 5
3 5
4 5
1 2 1
1 1 1
2 2 2 3 1

樣例 2
見選手目錄下的 center/center2.in 與 center/center2.ans 。

Sample Output

4
5
5
Sample Output

Data Constraint

Data Constraint
題目更正:di,j值域在int範圍內;q小於等於100000

Solution

  • 這題暴力的話是 O ( n k ) O(n\sum k) ,就是預處理出兩點距離,然後枚舉點看其能否被到達。

  • 但是這樣顯然不能通過此題。

  • 考慮使用STL的 b i t s e t bitset 來優化並解決此題。

  • b i t s e t < N > f [ i ] [ j ] bitset<N>f[i][j] ,表示從點 i i 出發,走不超過 j j 的距離能到達的點的集合。

  • 這樣設的空間複雜度是 O ( n 3 32 ) O(\frac{n^3}{32}) 的,不會爆空間(卡得還真緊……)。

  • 於是我們預處理 f f ,比如到一個點 i i 走距離 d d 恰好走到 x x ,則 f [ i ] [ d ] [ x ] = 1 f[i][d][x]=1

  • 最後對 f [ i ] f[i] 做一遍前綴或運算即可,即: f [ i ] [ j ]   = f [ i ] [ j 1 ] f[i][j]\ |=f[i][j-1]

  • 那麼回答詢問就容易啦!將每個 f [ x ] [ d ] f[x][d] 或起來,輸出 b i t s e t bitset 集合中 1 1 的個數就好了。

  • 然而這題還要卡常,如果用前向星等鏈表、vector存儲邊的話還會 T L E TLE

  • 爲了尋址複雜度更優,我們可以用鄰接表來存邊。。

  • 注意還要用一個鄰接矩陣來判斷重邊,不然還會爆鄰接表數組。。(自環當然也要判)

  • 時空複雜度 O ( n 3 32 ) O(\frac{n^3}{32})

Code

#include<cstdio>
#include<cstring>
#include<bitset>
#include<cctype>
using namespace std;
const int N=1005;
int a[N][N],dis[N],que[N],mx[N];
bool bz[N][N];
bitset<N>f[N][N],ans;
inline int read()
{
	int X=0,w=0; char ch=0;
	while(!isdigit(ch)) w|=ch=='-',ch=getchar();
	while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
	return w?-X:X;
}
void write(int x)
{
	if(x>9) write(x/10);
	putchar(x%10+'0');
}
inline int min(int x,int y)
{
	return x<y?x:y;
}
int main()
{
	freopen("center.in","r",stdin);
	freopen("center.out","w",stdout);
	int n=read(),m=read(),q=read();
	for(int i=1;i<=m;i++)
	{
		int x=read(),y=read();
		if(x==y || bz[x][y]) continue;
		a[x][++a[x][0]]=y;
		a[y][++a[y][0]]=x;
		bz[x][y]=bz[y][x]=true;
	}
	for(int i=1;i<=n;i++)
	{
		memset(dis,60,sizeof(dis));
		dis[que[1]=i]=0;
		f[i][0][i]=1;
		int l=0,r=1;
		while(l<r)
		{
			int x=que[++l];
			for(int j=1;j<=a[x][0];j++)
			{
				int y=a[x][j];
				if(dis[x]+1<dis[y])
				{
					f[i][dis[y]=dis[x]+1][y]=1;
					que[++r]=y;
				}
			}
		}
		int up=mx[i]=dis[que[r]];
		for(int j=1;j<=up;j++) f[i][j]|=f[i][j-1];
	}
	while(q--)
	{
		ans.reset();
		int k=read();
		while(k--)
		{
			int x=read(),d=min(mx[x],read());
			ans|=f[x][d];
		}
		write(ans.count()),putchar('\n');
	}
	return 0;
}