Travel
Time Limit: 1500/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 4433 Accepted Submission(s): 1466
For each test case, the first line consists of three integers n,m and q where n≤20000,m≤100000,q≤5000. The Undirected Kingdom has n cities and m bidirectional roads, and there are q queries.
Each of the following m lines consists of three integers a,b and d where a,b∈{1,...,n} and d≤100000. It takes Jack d minutes to travel from city a to city b and vice versa.
Then q lines follow. Each of them is a query consisting of an integer x where x is the time limit before Jack goes berserk.
Note that (a,b) and (b,a) are counted as different pairs and a and b must be different cities.
题目描述:输入一个t,测试样例的个数,第二行由三个数n,m,q组成,输入一个n,城市的个数,输入一个m,路线的条数,输入一个q,q个询问,接下来m行由a,b,d组成,其中a,b为城市的编号,d表示两个城市之间的距离,最后q行由一个数x组成,表示能忍受的最长距离
输出在有多少个城市对满足Jack不会发疯的条件.
注意:每到一个新城市 jack的怒气会回复到0 城市对(1,2)和城市对(2,1)表示两个不同的对.
离线带权并查集(表示完全不知道是什么东西,大佬说什么就是什么)
做法就是把城市按相距的距离从小到大排序一遍,同时询问也从小到大排序一遍(附上代码)
struct LX
{
int st;
int ed;
int s;
bool operator < (const LX lx1) const
{
return s<lx1.s;
}
}lx[max_m];
struct Q
{
int di;
int id;
bool operator < (const Q q1) const
{
return di<q1.di;
}
}q[5005];
之后就用并查集把城市之间连起来,用同一个父节点表示
int findf(int x)
{
return x==root[x]?x:root[x]=findf(root[x]);//不断更新
}
然后按询问从小到大遍历一遍所有联通的城市(就算城市不止由一棵树构成,或者说就算一棵树上的城市之间的距离大于jack的暴怒值,jack也可以在距离小于暴怒值的城市间来回,就是说你要找到所有城市距离小于暴怒值的个数)(终于说清了~~~~~~~~~~)
当你查询到不同的树时可到达城市对的个数增加了sum[1]*sum[2]个(其实是sum[1]*sum[2]*2个)但我们先记为增加了这么多
同时把这两棵数合并成一棵,然后神奇操作来了
inline void unio(int x,int y)
{
x=findf(x);y=findf(y);
if(sum[x]>sum[y])
{
sum[x]+=sum[y];
root[y]=x;
}
else
{
sum[y]+=sum[x];
root[x]=y;
}
}
平时我们合并的话可能是随便把一个当成父节点让另一个变成他的子节点,在这里我们让更大的那个变成父节点,另一个变成子节点
这样的话父节点的儿子会越变越多,这样在后面合并树的时候会显得很方便直接
之后只需要把每一个询问遍历得到的答案按询问的顺序存在一个数组里面就好了
最后按询问的顺序西输出就好了
注意之前我们只是按城市编号从小到大遍历了一遍,所以对于每一个询问只给出了一半的坐标.所以输出的时候需要乘一个2.
在这个题目里面输出ans[a]*2是会超时的,需要用到位运算输出ans[a]<<1,不然会超时的(我就超时了几遍差点心态炸了)
附上ac代码:
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int max_m=100000+5;
const int max_n=20000+5;
struct LX
{
int st;
int ed;
int s;
bool operator < (const LX lx1) const
{
return s<lx1.s;
}
}lx[max_m];
struct Q
{
int di;
int id;
bool operator < (const Q q1) const
{
return di<q1.di;
}
}q[5005];
int root[max_n];
int sum[max_n];
int ans[5005];
int n,m,qt;
int findf(int x)
{
return x==root[x]?x:root[x]=findf(root[x]);
}
inline void unio(int x,int y)
{
x=findf(x);y=findf(y);
if(sum[x]>sum[y])
{
sum[x]+=sum[y];
root[y]=x;
}
else
{
sum[y]+=sum[x];
root[x]=y;
}
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
for(int m1=1;m1<=m;m1++)
{
scanf("%d%d%d",&lx[m1].st,&lx[m1].ed,&lx[m1].s);
}
sort(lx+1,lx+m+1);
for(int q1=1;q1<=qt;q1++)
{
scanf("%d",&q[q1].di);
q[q1].id=q1;
}
sort(q+1,q+1+qt);
for(int n1=1;n1<=n;n1++)
{
root[n1]=n1;
sum[n1]=1;
}
int j=0;
int m1=1,q1=1;
for(;q1<=qt;q1++)
{
for(;m1<=m&&lx[m1].s<=q[q1].di;m1++)
{
if(findf(lx[m1].st)==findf(lx[m1].ed))
{
continue;
}
j=j+sum[findf(lx[m1].st)]*sum[findf(lx[m1].ed)];
unio(lx[m1].st,lx[m1].ed);
}
ans[q[q1].id]=j;
}
for(int q1=1;q1<=qt;q1++)
{
printf("%d\n",ans[q1]<<1);
}
}
return 0;
}