Luogu4149 [IOI2011]Race

本文详细解析了Luogu4149[IOI2011]Race题目,介绍了如何通过优化子树统计算法解决复杂问题,采用特殊的数据结构和算法技巧,避免重复统计,实现高效求解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Luogu4149 [IOI2011]Race

真真正正的淀粉质模板题。

为什么?之前那个O(N^2)检验子树的算法对于菊花图就很呵呵。

这个题,难点在于对子树的统计。

我们无法使用容斥一类的思想。

但是我们可以使用一种其他的方法。

也就是利用其中一颗的子树与其他子树的信息进行统计答案。

这样的话,就可以保证同一个子树内的信息不会被统计多次。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>

/*using std::min;
using std::max;*/

const int N=201000;
const int K=1010000;
const int inf=0x7ffffff;

struct node
{
    int p;
    int value;
    int nxt;
};

node line[N<<1];
int head[N],tail;
int size[N],f[N],vis[N];
int root,sum,ans;
int T[K];
int n,k;

int max(int a,int b)
{
    return a > b ? a : b ;
}

int min(int a,int b)
{
    return a < b ? a : b ;
}

int read()
{
    int res=0,flag=1;
    char c=getchar();
    while(c>'9'||c<'0')
    {
        if(c=='-') flag=-1;
        c=getchar();
    }
    while(c>='0'&&c<='9')
    {
        res=(res<<1)+(res<<3)+c-'0';
        c=getchar();
    }
    return res*flag;
}

void add(int a,int b,int c)
{
    line[++tail].p=b;
    line[tail].value=c;
    line[tail].nxt=head[a];
    head[a]=tail;
    return ;
}

void get_hry(int now,int fa)
{
    size[now]=1;f[now]=0;
    int v;
    for(int i=head[now];i;i=line[i].nxt)
    {
        v=line[i].p;
        if(vis[v]||v==fa)   continue;
        get_hry(v,now);
        f[now]=max(f[now],size[v]);
        size[now]+=size[v];
    }
    f[now]=max(f[now],sum-size[now]);
    if(f[root]>f[now])  root=now;
    return ;
}

void get_DD(int now,int fa,int Dis,int Dep)
{
    if(Dis>k)  return ;
    ans=min(ans,T[k-Dis]+Dep);
    int v;
    for(int i=head[now];i;i=line[i].nxt)
    {
        v=line[i].p;
        if(v==fa||vis[v])   continue;
        get_DD(v,now,Dis+line[i].value,Dep+1);
    }
    return ;
}

void updata(int now,int fa,int Dis,int Dep,int model)
{
    if(Dis>k)    return ;
    if(model)   T[Dis]=min(T[Dis],Dep);
    else    T[Dis]=inf;
    int v;
    for(int i=head[now];i;i=line[i].nxt)
    {
        v=line[i].p;
        if(v==fa||vis[v])   continue;
        updata(v,now,Dis+line[i].value,Dep+1,model);
    }
    return ;
}

void solve(int now)
{
    vis[now]=1;
    T[0]=0;
    int v;
    for(int i=head[now];i;i=line[i].nxt)
    {
        v=line[i].p;
        if(vis[v])  continue;
        get_DD(v,now,line[i].value,1);
        //ADD();
        updata(v,now,line[i].value,1,1);;
    }
    for(int i=head[now];i;i=line[i].nxt)
    {
        v=line[i].p;
        if(vis[v])  continue;
        updata(v,now,line[i].value,1,0);
    }
    for(int i=head[now];i;i=line[i].nxt)
    {
        v=line[i].p;
        if(vis[v])  continue;
        sum=size[v];root=0;
        get_hry(v,now);
        solve(root);
    }
    return ;
}

int main()
{
    //scanf("%d%d",&n,&k);
    n=read(),k=read();
    for(int i=1;i<=k;i++)   T[i]=inf;
    for(int i=1,a,b,c;i<n;i++)
    {
        //scanf("%d%d%d",&a,&b,&c);
        a=read(),b=read(),c=read();
        add(a+1,b+1,c);
        add(b+1,a+1,c);
    }
    root=0;sum=n;
    f[0]=inf;ans=inf;
    get_hry(1,0);
    solve(root);
    if(ans!=inf)
        printf("%d",ans);
    else
        printf("-1");
    return 0;
}

转载于:https://www.cnblogs.com/Lance1ot/p/10293310.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值