bzoj 2599 [IOI2011]Race 未调完_点分治

Code:

// luogu-judger-enable-o2
// luogu-judger-enable-o2
#include <bits/stdc++.h>
#define setIO(s) freopen(s".in","r",stdin)
#define maxn 1000000
#define inf 0x7f7f7f
using namespace std;
int hd[maxn],to[maxn],nex[maxn],val[maxn],f[maxn],vis[maxn],siz[maxn],dep[maxn],ans,cur=0;
int cnt,n,k,root,sn,d[2];
void addedge(int u,int v,int c)
{
    nex[++cnt] = hd[u],hd[u] = cnt,to[cnt] = v,val[cnt] = c;
}
struct Point{
    int dis,tot;
    Point(int dis = 0,int tot = 0):dis(dis),tot(tot){}
    bool operator<(Point b)const{
        return b.dis != dis ? b.dis>dis : b.tot > tot;
    }
}point[2][maxn];
void getdis(int u,int fa,int tot)
{
    point[cur][++d[cur]]=Point(dep[u],tot);
    for(int i = hd[u]; i ; i = nex[i])
    {
        if(vis[to[i]] || to[i] == fa) continue;
        dep[to[i]] = dep[u] + val[i],getdis(to[i],u,tot + 1);
    }
}
void GetRoot(int u,int ff)
{
    siz[u] = 1,f[u] = 0;
    for(int i = hd[u]; i ; i = nex[i])
    {
        if(vis[to[i]] || to[i] == ff) continue;
        GetRoot(to[i],u);
        siz[u] += siz[to[i]];
        f[u] = max(f[u], siz[to[i]]);
    }
    f[u] = max(f[u], sn - siz[u]);
    if(f[u] < f[root]) root = u;
}
void DFS(int u)
{
    vis[u] = 1, dep[u] = 0, cur = 0, d[cur] = 0,d[cur^1] = 1,point[cur^1][1] = Point(0,0);
    for(int i = hd[u]; i ; i = nex[i])
    {
        if(vis[to[i]]) continue;
        dep[to[i]] = val[i];
        d[cur] = 0;
        root = 0,sn = siz[to[i]],GetRoot(to[i],u), DFS(root);
        getdis(to[i],0,1);
        sort(point[cur]+1,point[cur]+1+d[cur]);
        int m = 1;
        for(int j = 2;j <= d[cur]; ++j) if(point[cur][j].dis!=point[cur][j-1].dis) point[cur][++m]=point[cur][j];
        d[cur] = m;
        int p1 = 1,p2 = d[cur^1];
        while(p1 <= d[cur] && p2 >=1)
        {
            if(point[cur][p1].dis + point[cur^1][p2].dis == k) ans = min(ans,point[cur][p1].tot + point[cur^1][p2].tot), ++p1,--p2;
            if(point[cur][p1].dis + point[cur^1][p2].dis < k) ++p1;
            if(point[cur][p1].dis + point[cur^1][p2].dis > k) --p2;
        }
        for(int j = 1;j <= d[cur]; ++j) point[cur^1][++d[cur^1]] = point[cur][j];
        sort(point[cur^1]+1,point[cur^1]+1+d[cur^1]);
        m = 1;
        for(int j=2;j<=d[cur^1];++j) if(point[cur^1][j].dis!=point[cur^1][j-1].dis)point[cur^1][++m]=point[cur^1][j];
        d[cur^1]=m, d[cur]=0;
    }
}
int main()
{
    setIO("input");
    scanf("%d%d",&n,&k);
    for(int i = 1,a,b,c;i < n; ++i) scanf("%d%d%d",&a,&b,&c),addedge(a+1,b+1,c),addedge(b+1,a+1,c);
    ans = inf, vis[0] = 1,f[0] = inf,sn = n,root = 0, GetRoot(1,0),DFS(root);
    printf("%d\n",ans==inf?-1:ans);
    return 0;
}

  

原文地址:https://www.cnblogs.com/guangheli/p/10939790.html

时间: 2024-10-08 08:16:31

bzoj 2599 [IOI2011]Race 未调完_点分治的相关文章

BZOJ 2599: [IOI2011]Race( 点分治 )

数据范围是N:20w, K100w. 点分治, 我们只需考虑经过当前树根的方案. K最大只有100w, 直接开个数组CNT[x]表示与当前树根距离为x的最少边数, 然后就可以对根的子树依次dfs并更新CNT数组和答案. ------------------------------------------------------------------------------------------ #include<bits/stdc++.h> using namespace std; typ

【刷题】BZOJ 2599 [IOI2011]Race

Description 给一棵树,每条边有权.求一条简单路径,权值和等于K,且边的数量最小.N <= 200000, K <= 1000000 Input 第一行 两个整数 n, k 第二..n行 每行三个整数 表示一条无向边的两端和权值 (注意点的编号从0开始) Output 一个整数 表示最小边数量 如果不存在这样的路径 输出-1 Sample Input 4 3 0 1 1 1 2 2 1 3 4 Sample Output 2 Solution 点分治 考虑如何计算答案,有一个节点,我

bzoj 2599 [IOI2011]Race (点分治)

[题意] 问树中长为k的路径中包含边数最少的路径所包含的边数. [思路] 统计经过根的路径.假设当前枚举到根的第S个子树,若x属于S子树,则有: ans<-dep[x]+min{ dep[y] },y属于前S-1个子树,dis[x]<=K 所以只需要用一个数组t[len]记录前S-1棵子树中长度为len的最少边数即可.t只用开到K的最大值. 然后分治处理子树. [代码] 1 #include<set> 2 #include<cmath> 3 #include<qu

2599. [IOI2011]Race【点分治】

Description 给一棵树,每条边有权.求一条简单路径,权值和等于K,且边的数量最小.N <= 200000, K <= 1000000 Input 第一行 两个整数 n, k 第二..n行 每行三个整数 表示一条无向边的两端和权值 (注意点的编号从0开始) Output 一个整数 表示最小边数量 如果不存在这样的路径 输出-1 Sample Input 4 3 0 1 1 1 2 2 1 3 4 Sample Output 2 开一个100W的数组t,t[i]表示到当前处理的树的根距离

bzoj 2599(点分治)

2599: [IOI2011]Race Time Limit: 70 Sec  Memory Limit: 128 MBSubmit: 3642  Solved: 1081[Submit][Status][Discuss] Description 给一棵树,每条边有权.求一条简单路径,权值和等于K,且边的数量最小.N <= 200000, K <= 1000000 Input 第一行 两个整数 n, k第二..n行 每行三个整数 表示一条无向边的两端和权值 (注意点的编号从0开始) Outpu

【BZOJ2599】[IOI2011]Race 树的点分治

[BZOJ2599][IOI2011]Race Description 给一棵树,每条边有权.求一条简单路径,权值和等于K,且边的数量最小.N <= 200000, K <= 1000000 Input 第一行 两个整数 n, k第二..n行 每行三个整数 表示一条无向边的两端和权值 (注意点的编号从0开始) Output 一个整数 表示最小边数量 如果不存在这样的路径 输出-1 Sample Input 4 3 0 1 1 1 2 2 1 3 4 Sample Output 2 题解:本题大

BZOJ 2599 Race(树分治)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2599 题意:给一棵树,每条边有权.求一条路径,权值和等于K,且边的数量最小. 题意:每次找到当前树的重心作为树根,查找通过当前树根的路径. 1 #include<algorithm> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstring> 5 #include<iostream>

BZOJ 2599 Race

点分写挂调一上午. #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<set> #define maxv 200050 #define maxe 400050 #define maxk 1000050 #define inf 1000000007 using namespace std; int n,k,x,y,w,g[maxv],

bzoj1758 [Wc2010]重建计划 &amp; bzoj2599 [IOI2011]Race

两题都是树分治. 1758这题可以二分答案avgvalue,因为avgvalue=Σv(e)/s,因此二分后只需要判断Σv(e)-s*avgvalue是否大于等于0,若大于等于0则调整二分下界,否则调整二分上界.假设一棵树树根为x,要求就是经过树根x的最大答案,不经过树根x的可以递归求解.假设B[i]为当前做到的一颗x的子树中的点到x的距离为i的最大权值,A[i]为之前已经做过的所有子数中的点到x的距离为i的最大权值(这里的权值是Σv(e)-i*avgvalue),那么对于当前子树的一个距离i,