题目大意:给一棵树,每条边有权。求一条路径,权值和等于K,且边的数量最小。
思路:BZ上没写数据范围,看了别人的博客发现是20w的点数。与正常的树分治的题不太一样,这个题每次统计答案不能只返回一个最值,而是要把所有的状态都存起来,方便在子树中删除的时候删掉。所以就有一个ans[i],表示路径数量是i的时候,答案的数量。其他的这个题的小细节特别多,一个函数传5个参伤不起啊。。。
CODE:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX 200010
#define INF 0x3f3f3f3f
using namespace std;
struct Complex{
int dis,step;
bool operator <(const Complex &a)const {
return dis < a.dis;
}
}temp[MAX];
int points,k;
int head[MAX],total;
int next[MAX << 1],aim[MAX << 1],length[MAX << 1];
bool v[MAX];
int root,size[MAX],_size,_total;
int p,cnt[MAX];
int ans[MAX];
inline void Add(int x,int y,int len);
void Work(int x);
void GetRoot(int x,int last);
inline void Count(int x,int last,int len,int c,int step);
void GetDis(int x,int last,int len,int step);
int main()
{
cin >> points >> k;
for(int x,y,z,i = 1;i < points; ++i) {
scanf("%d%d%d",&x,&y,&z);
x++,y++;
Add(x,y,z),Add(y,x,z);
}
Work(1);
int flag = -1;
for(int i = 1;i < MAX; ++i)
if(ans[i]) {
flag = i;
break;
}
cout << flag << endl;
return 0;
}
inline void Add(int x,int y,int len)
{
next[++total] = head[x];
aim[total] = y;
length[total] = len;
head[x] = total;
}
void Work(int x)
{
_size = INF,_total = size[x] ? size[x]:points;
GetRoot(x,0);
x = root;
v[x] = true;
Count(x,0,0,1,0);
for(int i = head[x];i;i = next[i]) {
if(v[aim[i]]) continue;
Count(aim[i],x,length[i],-1,1);
Work(aim[i]);
}
}
void GetRoot(int x,int last)
{
size[x] = 1;
int max_size = 0;
for(int i = head[x];i;i = next[i]) {
if(v[aim[i]] || aim[i] == last) continue;
GetRoot(aim[i],x);
size[x] += size[aim[i]];
max_size = max(max_size,size[aim[i]]);
}
max_size = max(max_size,_total - size[x]);
if(max_size < _size)
_size = max_size,root = x;
}
inline void Count(int x,int last,int len,int c,int step)
{
p = 0;
GetDis(x,last,len,step);
sort(temp + 1,temp + p + 1);
int l = 1,r = p;
while(l < r) {
if(temp[l].dis + temp[r].dis > k) --r;
else if(temp[l].dis + temp[r].dis < k) ++l;
else {
int _l = l;
while(temp[_l + 1].dis == temp[l].dis) ++_l;
int _r = r;
while(temp[_r - 1].dis == temp[r].dis) --_r;
for(int i = l;i <= _l; ++i)
for(int j = _r;j <= r; ++j)
if(i != j)
ans[temp[i].step + temp[j].step] += c;
l = _l + 1,r = _r - 1;
}
}
}
void GetDis(int x,int last,int len,int step)
{
temp[++p].dis = len;
temp[p].step = step;
for(int i = head[x];i;i = next[i]) {
if(aim[i] == last || v[aim[i]]) continue;
GetDis(aim[i],x,len + length[i],step + 1);
}
}