题目: | How Many Pairs? | |
来源: | Pku 2832 | |
题目大意: | 题意让我理解了半天,果然英语不好。 其实就是n个点m条边q次访问,每次输出任何一对点只要其所经过的边的最长边比 访问值小就行的有效点数量 | |
数据范围: | 1 < N ≤ 10,000, 0 < M ≤ 50,000, 0 < Q ≤ 10,000 | |
样例: | 4 5 4 1 2 1 2 3 2 2 3 5 3 4 3 4 1 4 0 1 3 2 | 0 1 6 3 |
做题思路: | 如果题意看懂了貌似就不那么难了,写的是类似kruskal的,所以就那么叫了。先把 访问值和边按从小到大排了,然后并查集合并,合并时注意减去重复的 | |
知识点: | 并查集、kruskal |
type
act=record
x,y,d:longint;
end;
atp=array[0..50000]of longint;
var
a:array[0..50010]of act;
ans,time,tot,b,f:array[0..50000]of longint;
n,i,q,m,x,y,d:longint;
procedure qsorta(l,r:longint);
var
i,j,k:longint;
t:act;
begin
i:=l;j:=r;
k:=a[(l+r)shr 1].d;
repeat
whilea[i].d<k do inc(i);
whilea[j].d>k do dec(j);
ifi<=j then
begin
t:=a[i];a[i]:=a[j];a[j]:=t;
inc(i);dec(j);
end;
untili>j;
ifi<r then qsorta(i,r);
ifj>l then qsorta(l,j);
end;
procedure qsortb(l,r:longint;vart:atp);{<t数组是形变参。。。>}
var
tmp,i,j,k:longint;
begin
i:=l;j:=r;
k:=t[(l+r)shr 1];
repeat
whilet[i]<k do inc(i);
whilet[j]>k do dec(j);
ifi<=j then
begin
tmp:=t[i];t[i]:=t[j];t[j]:=tmp;
tmp:=time[i];time[i]:=time[j];time[j]:=tmp;
inc(i);dec(j);
end;
untili>j;
ifi<r then qsortb(i,r,t);
ifj>l then qsortb(l,j,t);
end;
function getf(x:longint):longint;
begin
iff[x]=x then exit(x);
f[x]:=getf(f[x]);
exit(f[x]);
end;
procedure union(x,y:longint);
begin
f[x]:=y;
end;
procedure kruskal;{<好像kruskal所以就这么命名啦>}
var
i,j,last,x,y:longint;
begin
fori:=1 to n do
begin
f[i]:=i;
tot[i]:=1;{<初始化对应点>}
end;
fillchar(ans,sizeof(ans),0);
last:=1;
fori:=1 to q do
begin
ans[time[i]]:=ans[time[i-1]];{<访问值再time下是越来越大的,所以可以先把之前求出来的赋给要求的>}
forj:=last to m do
begin
ifa[j].d>b[i] then{<由于对边排序了,所以第一个大于访问值的就是第一个大于的>}
begin
last:=j;
break;
end;
x:=getf(a[j].x);y:=getf(a[j].y);
ifx<>y then
begin
union(x,y);
ans[time[i]]:=ans[time[i]]-tot[x]*(tot[x]-1) div 2-tot[y]*(tot[y]-1) div2;{<累计答案是要注意不要让对应点重复了,所以先减后加>}
tot[y]:=tot[x]+tot[y];
ans[time[i]]:=ans[time[i]]+tot[y]*(tot[y]-1)div 2;
end;
end;
end;
end;
begin
readln(n,m,q);
fori:=1 to m do
begin
witha[i] do{<记录性特有滴。。>}
readln(x,y,d);
end;
fori:=1 to q do
begin
time[i]:=i;{<排序就不动原数了,以免输出时麻烦,所以把序号排了>}
readln(b[i]);
end;
qsorta(1,m);
qsortb(1,q,b);
kruskal;
fori:=1 to q do writeln(ans[i]);
end.
题目来源:
http://poj.org/problem?id=2832