题目大意:在坐标轴的第一象限有个点,给定
,
和点的扩散速度
(按圆形扩散,范围相交视为在同一连通块上),给定
个询问,询问时间为
时连通块的数量
分析:不妨将每个点两两连边,边的权值为两点成为同一连通块的时间,可以发现此时问题便转化成求这张图的最小生成树类的问题,求出连通块数量减少时的时间。对于问题采用离线处理,易求出答案
参考代码:
#define LL long long
using namespace std;
const int M=1005;
int n,q;
struct Edge{
int u,v;
double w,tim;
}e[M*M];
struct Node{
int val,id,anq;
}ask[M];
int fa[M],x[M],y[M],vv[M];
double timset[M];
int findfa(int x){
if(fa[x]==x) return x;
return fa[x]=findfa(fa[x]);
}
bool Cmp(Edge u1,Edge v1){
return u1.tim<v1.tim;
}
bool Cmp2(Node u2,Node v2){
return u2.val<v2.val;
}
bool Cmp3(Node u3,Node v3){
return u3.id<v3.id;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d%d%d",&x[i],&y[i],&vv[i]);
fa[i]=i;
}
scanf("%d",&q);
for(int i=1;i<=q;i++){
scanf("%d",&ask[i].val);
ask[i].id=i;
}
sort(ask+1,ask+1+q,Cmp2);
int cnt=0;
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++){
e[++cnt].u=i; e[cnt].v=j; e[cnt].w=1.0*sqrt(1.0*(x[i]-x[j])*(x[i]-x[j])+1.0*(y[i]-y[j])*(y[i]-y[j]));
e[cnt].tim=1.0*e[cnt].w/(1.0*vv[i]+1.0*vv[j]);
//cout<<"G"<<e[cnt].w<<"\n";
//cout<<"T"<<e[cnt].tim<<" ";
}
}
int num=n,tot=1;
timset[0]=0;
sort(e+1,e+1+cnt,Cmp);
for(int i=1;i<=cnt;i++){
int lfa=findfa(e[i].u);
int rfa=findfa(e[i].v);
if(lfa!=rfa){
timset[tot]=e[i].tim; tot++;
fa[lfa]=rfa; num--;
}
}
//for(int i=1;i<=tot;i++) cout<<timset[i]<<" ";
tot=1;
for(int i=1;i<=q;i++)
{
while(ask[i].val>=timset[tot]&&tot<n){
tot++;
}
ask[i].anq=n-(tot-1);
}
sort(ask+1,ask+1+q,Cmp3);
for(int i=1;i<=q;i++){
printf("%d\n",ask[i].anq);
}
}