题目大意:给一棵树,每条边有权。求一条路径,权值和等于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); } }