BZOJ 3365: [Usaco2004 Feb]Distance Statistics 路程统计【点分治】

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

【题目描述】
传送门

【题解】

题目中的方向和m是没用的,m永远等于n-1。那么就是简单的点分治了。

代码如下

#include<cstdio>
#include<algorithm>
#define MAXN 40005
using namespace std;
int n,m,K,Rot,RotSize,Ans;
int Siz[MAXN],dst[MAXN],Maxs[MAXN],Stk[MAXN],TOP;
bool vis[MAXN];
struct Edge{
    int tot,lnk[MAXN],son[MAXN<<1],nxt[MAXN<<1],W[MAXN<<1];
    void Add(int x,int y,int z){son[++tot]=y;W[tot]=z;nxt[tot]=lnk[x];lnk[x]=tot;}
}E;
void Get_Rot(int x,int fa){
    Siz[x]=1;Maxs[x]=0;
    for(int j=E.lnk[x];j;j=E.nxt[j])
    if(!vis[E.son[j]]&&E.son[j]!=fa){
        Get_Rot(E.son[j],x);Siz[x]+=Siz[E.son[j]];
        Maxs[x]=max(Maxs[x],Siz[E.son[j]]);
    }
    Maxs[x]=max(Maxs[x],RotSize-Siz[x]);
    if(Maxs[x]<Maxs[Rot]) Rot=x;
}
void Get_Dst(int x,int fa){
    Siz[x]=1;Stk[++TOP]=dst[x];
    for(int j=E.lnk[x];j;j=E.nxt[j])
    if(!vis[E.son[j]]&&E.son[j]!=fa){
        dst[E.son[j]]=dst[x]+E.W[j];
        Get_Dst(E.son[j],x);
        Siz[x]+=Siz[E.son[j]];
    }
}
int Cal(int x,int Now){
    TOP=0;dst[x]=Now;Get_Dst(x,0);
    sort(Stk+1,Stk+1+TOP);
    int Ret=0;
    for(int l=1,r=TOP;l<r;l++){
        while(Stk[l]+Stk[r]>K&&l<r) r--;
        Ret+=r-l;
    }
    return Ret;
}
void Solve(int x){
    Ans+=Cal(x,0);vis[x]=1;
    for(int j=E.lnk[x];j;j=E.nxt[j])
    if(!vis[E.son[j]]){
        Ans-=Cal(E.son[j],E.W[j]);
        Maxs[0]=RotSize=Siz[E.son[j]];Rot=0;
        Get_Rot(E.son[j],0);
        Solve(Rot);
    }
}
int main(){
    #ifndef ONLINE_JUDGE
    freopen("prob.in","r",stdin);
    freopen("prob.out","w",stdout);
    #endif
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++){
        int x,y,z;char ch[10];scanf("%d%d%d%s",&x,&y,&z,ch);
        E.Add(x,y,z);E.Add(y,x,z);
    }
    scanf("%d",&K);
    Rot=0;RotSize=Maxs[0]=n;
    Get_Rot(1,0);
    Solve(Rot);
    printf("%d\n",Ans);
    return 0;
}

转载于:https://www.cnblogs.com/XSamsara/p/9838842.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值