bzoj3365: [Usaco2004 Feb]Distance Statistics 路程统计

链接

  http://www.lydsy.com/JudgeOnline/problem.php?id=3365

题解

  和bzoj1468是一样的吧,连样例、数据规模都完全一样。

代码

//点分治 
#include <cstdio>
#include <algorithm>
#define maxn 50000
#define forp for(int p=head[pos];p;p=nex[p])if(to[p]^pre and !grey[to[p]])
using namespace std;
int M, S, head[maxn], nex[maxn<<1], to[maxn<<1], w[maxn<<1], dist[maxn], size[maxn],
    list[maxn], G, sumG, ans, K, grey[maxn], tot, N;
inline void adde(int a, int b, int v)
{to[++tot]=b;w[tot]=v;nex[tot]=head[a];head[a]=tot;}
inline int calc()
{
    int l=1, r=*list, cnt=0;
    sort(list+1,list+*list+1);
    while(l<r)
    {
        while(l<r and list[l]+list[r]>K)r--;
        while(l<r and list[l]+list[r]<=K)cnt+=r-l,l++;
    }
    return cnt;
}
void dfs(int pos , int pre)
{
    list[++*list]=dist[pos];
    forp dfs(to[p],pos);
}
void calc_dist(int pos, int pre)
{
    list[++*list]=dist[pos];
    forp dist[to[p]]=dist[pos]+w[p], calc_dist(to[p],pos);
}
int calc_size(int pos, int pre)
{
    size[pos]=1;
    forp size[pos]+=calc_size(to[p],pos);
    return size[pos];
}
void findG(int pos, int pre, int sum)
{
//  printf("pos=%d sum=%d\n",pos,sum);
    if(sum<sumG)G=pos, sumG=sum;
    forp findG(to[p],pos,sum+(*size-size[to[p]])*w[p]-size[to[p]]*w[p]);
}
void solve(int pos)
{
    int p, x=0;
    if(G)*list=0, dfs(pos,-1), ans-=calc();
    dist[pos]=0, *list=0, calc_dist(pos,-1);
    calc_size(pos,-1), *size=size[pos];
    G=pos; for(int i=1;i<=*list;i++)x+=list[i]; sumG=x;
    findG(pos,-1,x);
    grey[G]=1;
    dist[G]=0, *list=0, calc_dist(G,-1);
    ans+=calc();
    for(p=head[G];p;p=nex[p])if(!grey[to[p]])solve(to[p]);
}
void init()
{
    int i, a, b, v;
    char s[5];
    scanf("%d%d",&N,&M);
    for(i=1;i<=M;i++)scanf("%d%d%d%s",&a,&b,&v,s), adde(a,b,v), adde(b,a,v), S=a;
    scanf("%d",&K);
}
int main()
{
    init();
    solve(S);
    printf("%d",ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值