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

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

------------------------------------------------------------------------------------------

#include<bits/stdc++.h>

using namespace std;

typedef pair<int, int> pii;

const int maxn = 200009;

const int maxk = 1000009;

const int INF = 0x3F3F3F3F;

inline int read() {

int ret = 0;

char c = getchar();

for(; !isdigit(c); c = getchar());

for(; isdigit(c); c = getchar())

ret = ret * 10 + c - ‘0‘;

return ret;

}

int N, K, size[maxn], Rt, best, n, CNT[maxk], _n, ANS = INF;

pii T[maxn];

bool vis[maxn];

struct edge {

int to, w;

edge* next;

} E[maxn << 1], *pt = E, *head[maxn];

inline void add(int u, int v, int w) {

pt->to = v; pt->w = w; pt->next = head[u]; head[u] = pt++;

}

inline void addedge(int u, int v, int w) {

add(u, v, w); add(v, u, w);

}

void dfs(int x, int fa = -1) {

size[x] = 1;

int mx = 0;

for(edge* e = head[x]; e; e = e->next) if(e->to != fa && !vis[e->to]) {

dfs(e->to, x);

size[x] += size[e->to];

mx = max(mx, size[e->to]);

}

if((mx = max(mx, n - size[x])) < best) Rt = x, best = mx;

}

void DFS(int x, int dist, int cnt, int fa) {

if(dist > K) return;

ANS = min(ANS, cnt + CNT[K - dist]);

T[_n++] = make_pair(dist, cnt++);

for(edge* e = head[x]; e; e = e->next) if(e->to != fa && !vis[e->to])

DFS(e->to, dist + e->w, cnt, x);

}

void solve(int x) {

best = INF; dfs(x); x = Rt;

int p = _n = 0;

for(edge* e = head[x]; e; e = e->next) if(!vis[e->to]) {

DFS(e->to, e->w, 1, x);

for(int i = p; i < _n; i++)

CNT[T[i].first] = min(CNT[T[i].first], T[i].second);

p = _n;

}

for(int i = 0; i < _n; i++) CNT[T[i].first] = INF; CNT[0] = 0;

vis[x] = true;

for(edge* e = head[x]; e; e = e->next) if(!vis[e->to]) {

n = size[e->to];

solve(e->to);

}

}

void init() {

N = read(); K = read();

for(int i = 1; i < N; i++) {

int u = read(), v = read(), w = read();

addedge(u, v, w);

}

}

int main() {

init();

n = N;

memset(CNT, INF, sizeof CNT); CNT[0] = 0;

solve(0);

printf("%d\n", ANS != INF ? ANS : -1);

return 0;

}

------------------------------------------------------------------------------------------

2599: [IOI2011]Race

Time Limit: 50 Sec  Memory Limit: 128 MB
Submit: 1806  Solved: 538
[Submit][Status][Discuss]

Description

给一棵树,每条边有权.求一条路径,权值和等于K,且边的数量最小.

Input

第一行 两个整数 n, k
第二..n行 每行三个整数 表示一条无向边的两端和权值 (注意点的编号从0开始)

Output

一个整数 表示最小边数量 如果不存在这样的路径 输出-1

Sample Input

4 3
0 1 1
1 2 2
1 3 4

Sample Output

2

HINT

Source

时间: 2024-08-06 11:30:00

BZOJ 2599: [IOI2011]Race( 点分治 )的相关文章

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

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

【刷题】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 点分治 考虑如何计算答案,有一个节点,我

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]表示到当前处理的树的根距离

IOI2011 Race [点分治]

题意 给一棵树,每条边有权.求一条简单路径,权值和等于 $K$,且边的数量最小. 点分治,求距离时带上经过边的数量即可.用的第一种写法(下面). 食用淀粉质注意事项 1. 统计子树内答案的两种写法: 跟树形dp一样将某子树与前面的子树合并   或者是   考虑所有子树的答案再容斥,减去不合法的一棵子树内答案. 2.好好写求重心,千万不要写假!!!假淀粉害死人 注意每次遍历先初始化$f[x]=0$,要有子树大小$S$. 1 #include <cstdio> 2 #include <cst

P4149 [IOI2011]Race 点分治

思路: 点分治 提交:5次 题解: 刚开始用排序+双指针写的,但是调了一晚上,总是有两个点过不了,第二天发现原因是排序时的\(cmp\)函数写错了:如果对于路径长度相同的,我们从小往大按边数排序,当双指针出现\(==k\)时,即我们应先左移右指针,否则答案可能会变劣(仔细想一想):若反着排序,应该先右移左指针. #include<bits/stdc++.h> #define R register int using namespace std; namespace Luitaryi { tem

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

【BZOJ-2599】Race 点分治

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

【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 题解:本题大