[Ynoi2015]我回來了
阿新 • • 發佈:2018-12-10
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]我回來了