【汕头市选2014】分叉(fork)

题目

Description

给出一棵N 个点的树,点的编号是1, 2,。。。,N。

对于3 个点{a,b,c},如果不存在一条简单路径同时经过a,b,c,那么{a,b,c}是一个分叉。

统计不同分叉的数量。

树 无环,连通的无向图

简单路径 不重复经过同一个点的路径

Input

第1 行,1 个整数N。接下来(N -1) 行,每行2 个整数Ai,Bi,表示点Ai 和点Bi 间有一条边。

Output

1 个整数,表示所求的值。

Sample Input

5

1 2

1 3

1 4

1 5

Sample Output

4

Data Constraint

• 对于30% 的数据,N <= 100;

• 对于50% 的数据,N <= 1000;

• 对于100% 的数据,1 <= N <= 10^5。

题解

我们可以反着做,也就是找出合法的{x,y,z}三元组
那么我们可以枚举y,而x和z分别在以y为根形成的树的两颗子树里面,计算每一个y对应的组数,这样就不会有重复的情况了

贴代码

var
    a,b:array[0..200005,1..2]of longint;
    father,son:array[0..100005]of longint;
    size:array[0..100005]of int64;
    bz:array[0..100005]of boolean;
    i,j,k,l,m,n,x,y,z:longint;
    ans,nn,p:int64;
procedure qsort(l,r:longint);
var
    i,j,mid:longint;
begin
    i:=l;
    j:=r;
    mid:=a[(i+j) div 2,1];
    repeat
        while a[i,1]<mid do inc(i);
        while a[j,1]>mid do dec(j);
        if i<=j then
        begin
            a[0]:=a[i];
            a[i]:=a[j];
            a[j]:=a[0];
            inc(i);
            dec(j);
        end;
    until i>j;
    if i<r then qsort(i,r);
    if l<j then qsort(l,j);
end;
procedure star;
begin
    b[a[1,1],1]:=1;
    for i:=2 to k do
    if a[i,1]<>a[i-1,1] then
    begin
        b[a[i-1,1],2]:=i-1;
        b[a[i,1],1]:=i;
    end;
    b[a[k,1],2]:=k;
end;
procedure dfs(x:longint);
var
    i:longint;
begin
    bz[x]:=true;
    for i:=b[x,1] to b[x,2] do
    if (i<>0) and (bz[a[i,2]]=false) then
    begin
        father[a[i,2]]:=x;
        inc(son[x]);
        dfs(a[i,2]);
        size[x]:=size[x]+size[a[i,2]];
    end;
    inc(size[x]);
end;
begin
    //assign(input,'t3.in'); reset(input);
    assign(input,'fork.in'); reset(input);
    assign(output,'fork.out'); rewrite(output);
    readln(n);
    for i:=1 to n-1 do
    begin
        readln(a[i,1],a[i,2]);
        a[i+n-1,1]:=a[i,2];
        a[i+n-1,2]:=a[i,1];
    end;
    k:=2*n-2;
    qsort(1,k);
    star;
    dfs(1);
    nn:=n;
    ans:=trunc(nn*(nn-1)/6*(nn-2));
    for i:=1 to n do
    if son[i]>0 then
    begin
        p:=0;
        for j:=b[i,1] to b[i,2] do
        if a[j,2]<>father[i] then
        begin
            ans:=ans-size[a[j,2]]*(nn-size[a[j,2]]-1-p);
            p:=p+size[a[j,2]];
        end;
    end;
    writeln(ans);
    close(input); close(output); 
end.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值