您的位置:首页 > 其它

bzoj 2599: [IOI2011]Race(树的点分治)

2017-10-05 14:02 330 查看

2599: [IOI2011]Race

Time Limit: 70 Sec  Memory Limit: 128 MB
Submit: 3862  Solved: 1144

[Submit][Status][Discuss]

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

http://blog.csdn.net/jaihk662/article/details/77429708

每次拉出重心,然后爆搜所有经过该节点的路径,看存不存在等于k的

#include<stdio.h>
#include<vector>
using namespace std;
typedef struct
{
int y;
int len;
}Point;
Point now, s[200005];
vector<Point> G[200005];
int ans, cnt, n, k, bet, heart, vis[200005], size[200005], dp[2000005], st[200005];
void Sech1(int u, int p)
{
int i, v;
size[u] = 1;
for(i=0;i<G[u].size();i++)
{
v = G[u][i].y;
if(v==p || vis[v])
continue;
Sech1(v, u);
size[u] += size[v];
}
}
void Sech2(int u, int p, int &psiz)
{
int bsiz, v, i;
bsiz = psiz-size[u];
for(i=0;i<G[u].size();i++)
{
v = G[u][i].y;
if(v==p || vis[v])
continue;
bsiz = max(bsiz, size[v]);
Sech2(v, u, psiz);
}
if(bsiz<bet)
{
bet = bsiz;
heart = u;
}
}
void Sech(int u, int p, int len, int now)
{
int i, v;
if(k-len>0 && dp[k-len]!=0 || k==len)
ans = min(ans, now+dp[k-len]);
if(k-len>0)
s[++cnt].y = now, s[cnt].len = len;
for(i=0;i<G[u].size();i++)
{
v = G[u][i].y;
if(vis[v] || v==p)
continue;
Sech(v, u, len+G[u][i].len, now+1);
}
}
void Count(int u)
{
int i, j, v, all;
all = 0;
for(i=0;i<G[u].size();i++)
{
v = G[u][i].y;
if(vis[v])
continue;
cnt = 0;
Sech(v, u, G[u][i].len, 1);
for(j=1;j<=cnt;j++)
{
if(dp[s[j].len]==0 && s[j].len!=0)
dp[s[j].len] = s[j].y, st[++all] = s[j].len;
else
dp[s[j].len] = min(dp[s[j].len], s[j].y);
}
}
if(dp[k]!=0)
ans = min(ans, dp[k]);
for(i=1;i<=all;i++)
dp[st[i]] = 0;
}
void Divide(int u)
{
int i, v;
Sech1(u, 0);
bet = 200005;
Sech2(u, 0, size[u]);
vis[heart] = 1;
u = heart;
Count(u);
for(i=0;i<G[u].size();i++)
{
v = G[u][i].y;
if(vis[v])
continue;
Divide(v);
}
}
int main(void)
{
int x, y, len, i;
//freopen("in.txt", "r", stdin);
scanf("%d%d", &n, &k);
for(i=1;i<=n-1;i++)
{
scanf("%d%d%d", &x, &y, &len);
x++, y++;
now.y = y, now.len = len;
G[x].push_back(now);
now.y = x;
G[y].push_back(now);
}
if(k==0)
{
printf("0\n");
return 0;
}
ans = 2345667;
Divide(1);
if(ans==2345667)
ans -= 2345668;
printf("%d\n", ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: