1. 程式人生 > >[Ynoi2015]我回來了

[Ynoi2015]我回來了

return bsp 時間 sta def ifd 太陽 size pan

題目大意:

給定一張無向無權圖,每次給定若幹個二元組\((x_i,y_i)\),定義點\(u\)滿足條件,當且僅當存在\(i\),並滿足\(dist(u,x_i)\leqslant y_i\)(\(dist(u,v)\)表示\(u,v\)兩點的距離)。每次詢問求滿足條件的點個數。

解題思路:

在太陽西斜的這個世界裏,置身天上之森。等這場戰爭結束之後,不歸之人與望眼欲穿的眾人, 人人本著正義之名,長存不滅的過去、逐漸消逝的未來。我回來了,縱使日薄西山,即便看不到未來,此時此刻的光輝,盼君勿忘。————世界上最幸福的女孩

珂朵莉,最可愛了呢。

---

我們定義\(f[i][j]\)為從點\(i\)出發,最短路小於等於\(j\)的點的集合。這個可以用bitset壓位存儲。

計算\(f[i][j]\),我們首先要知道任意兩點對間最短路,然後計算出從每個點出發,最短路恰好為\(j\)的點的集合。然後前綴或一遍就是\(f[i][j]\)。

計算都可以在\(O(\dfrac{n^3}{\omega})\)的復雜度內完成。

而求任意點對間最短路,就從每個點開始BFS一遍即可。時間復雜度\(O(n(n+m))\)。

最後處理詢問的時候,就把每個\((x,y)\)對應的\(f[x][y]\)都取並集,然後求其中1的個數即可。時間復雜度\(O(\dfrac{n\sum a}{\omega})\)。

總時間復雜度\(O(n(n+m)+\dfrac{n^3+n\sum a}{\omega})\),空間復雜度\(O(\dfrac{n^3}{\omega})\)。

然後聽說這道題卡前向星

似乎是由於訪問連續內存會比較快的原因,用vector存邊就跑的飛快,而前向星就T飛了。

C++ Code:

#include<bitset>
#include<cstdio>
#include<cctype>
#include<queue>
#include<vector>
#define N 1003
#ifdef ONLINE_JUDGE
struct istream{
	char buf[23333333],*s;
	inline istream(){
		buf[fread(s=buf,1,23333330,stdin)]=‘\n‘;
		fclose(stdin);
	}
	inline istream&operator>>(int&d){
		d=0;
		for(;!isdigit(*s);++s);
		while(isdigit(*s))
		d=(d<<3)+(d<<1)+(*s++^‘0‘);
		return*this;
	}
}cin;
#else
#include<iostream>
using std::cin;
#endif
std::bitset<N>a[N][N];
int n,m,q,dis[N][N];
std::vector<int>G[N];
void bfs(int s,int*dis){
	for(int i=1;i<=n;++i)dis[i]=1002;
	static std::queue<int>q;
	dis[s]=0;
	for(q.push(s);!q.empty();){
		int u=q.front();q.pop();
		for(int i:G[u])
		if(dis[i]==1002){
			dis[i]=dis[u]+1;
			q.push(i);
		}
	}
	for(int i=1;i<=n;++i)
	a[s][dis[i]].set(i);
	for(int i=1;i<=n;++i)a[s][i]|=a[s][i-1];
}
int main(){
	cin>>n>>m>>q;
	while(m--){
		int u,v;
		cin>>u>>v;
		G[u].push_back(v);
		G[v].push_back(u);
	}
	for(int i=1;i<=n;++i)bfs(i,dis[i]);
	while(q--){
		std::bitset<N>ans;
		int x,u,v;
		cin>>x;
		while(x--){
			cin>>u>>v;
			if(v>n)v=n;
			ans|=a[u][v];
		}
		printf("%d\n",ans.count());
	}
	return 0;
}

  

[Ynoi2015]我回來了