洛谷P4149 [IOI2011]Race(点分治)

题目描述

给一棵树,每条边有权。求一条简单路径,权值和等于 KK ,且边的数量最小。

输入输出格式

输入格式:

 

第一行:两个整数 n,kn,k 。

第二至 nn 行:每行三个整数,表示一条无向边的两端和权值 (注意点的编号从 00 开始)。

 

输出格式:

 

一个整数,表示最小边数量。

如果不存在这样的路径,输出 -11 。

 

输入输出样例

输入样例#1: 
4 3
0 1 1
1 2 2
1 3 4
输出样例#1: 
2

说明

n\le 200000,K\le 1000000n200000,K1000000 。

 

题解:谁说点分一定要套容斥的?

这题的暴力思路大约跟dp有点像,每次爆枚到一棵子树中每一个点的距离,显然对于这些距离di,能与他产生解的是之前所有子树中到达距离为k-di的点的最小深度。

然后就是一遍dfs爆枚所有点,再一遍dfs更新所有最小深度,然后就可以a掉了

 

代码如下:

#include<map>
#include<set>
#include<queue>
#include<cmath>
#include<cstdio>
#include<string>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#define mp make_pair
#define pii pair<int,int>
#define inf 0x3f3f3f3f
using namespace std;
#define int ll
typedef long long ll;
int n,k,deep[2000010],dis[2000010],size[2000010],fa[2000010],vis[2000010];
int tmp[10000010],ans;
vector<pii> g[2000100];

void get_size(int now,int f)
{
    size[now]=1;
    fa[now]=f;
    for(int i=0; i<g[now].size(); i++)
    {
        if(vis[g[now][i].first]||g[now][i].first==f) continue;
        get_size(g[now][i].first,now);
        size[now]+=size[g[now][i].first];
    }
}

int get_zx(int now,int f)
{
    if(size[now]==1) return now;
    int son,maxson=-1;
    for(int i=0; i<g[now].size(); i++)
    {
        if(vis[g[now][i].first]||g[now][i].first==f) continue;
        if(size[g[now][i].first]>maxson)
        {
            maxson=size[g[now][i].first];
            son=g[now][i].first;
        }
    }
    int zx=get_zx(son,now);
    while(size[zx]<2*(size[now]-size[zx])) zx=fa[zx];
    return zx;
}

void calc(int now,int f,int dep,int di)
{
    deep[now]=dep;
    dis[now]=di;
    if(dis[now]<=k) ans=min(ans,tmp[k-dis[now]]+deep[now]);
    else return;
    for(int i=0; i<g[now].size(); i++)
    {
        if(vis[g[now][i].first]||g[now][i].first==f) continue;
        calc(g[now][i].first,now,dep+1,di+g[now][i].second);
    }
}

void dfs(int now,int f,int kd)
{
    if(kd) tmp[dis[now]]=min(tmp[dis[now]],deep[now]);
    else tmp[dis[now]]=inf;
    for(int i=0;i<g[now].size();i++)
    {
        if(vis[g[now][i].first]||g[now][i].first==f) continue;
        dfs(g[now][i].first,now,kd);
    }
}

void solve(int now)
{
    vis[now]=1;
    tmp[0]=0;
    for(int i=0;i<g[now].size();i++)
    {
        if(vis[g[now][i].first]) continue;
        calc(g[now][i].first,0,1,g[now][i].second);
        dfs(g[now][i].first,0,1);
    }
    for(int i=0;i<g[now].size();i++)
    {
        if(vis[g[now][i].first]) continue;
        dfs(g[now][i].first,0,0);
    }
    for(int i=0;i<g[now].size();i++)
    {
        if(vis[g[now][i].first]) continue;
        get_size(g[now][i].first,0);
        int zx=get_zx(g[now][i].first,0);
        solve(zx);
    }
}

main()
{
    scanf("%lld%lld",&n,&k);
    for(int i=1;i<n;i++)
    {
        int from,to,cost;
        scanf("%lld%lld%lld",&from,&to,&cost);
        g[from+1].push_back(mp(to+1,cost));
        g[to+1].push_back(mp(from+1,cost));
    }
    ans=inf;
    memset(tmp,0x3f,sizeof(tmp));
    solve(1);
    ans==0x3f3f3f3f?puts("-1"):printf("%lld\n",ans);
}

 

posted @ 2018-08-06 20:46  Styx-ferryman  阅读(188)  评论(0编辑  收藏  举报