BZOJ 2599 IOI 2011 Race 树的分治

来源:互联网 发布:中国移动电视网络页面 编辑:程序博客网 时间:2024/06/06 14:28

题目大意:给一棵树,每条边有权。求一条路径,权值和等于K,且边的数量最小。


思路:BZ上没写数据范围,看了别人的博客发现是20w的点数。与正常的树分治的题不太一样,这个题每次统计答案不能只返回一个最值,而是要把所有的状态都存起来,方便在子树中删除的时候删掉。所以就有一个ans[i],表示路径数量是i的时候,答案的数量。其他的这个题的小细节特别多,一个函数传5个参伤不起啊。。。


CODE:

#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#define MAX 200010#define INF 0x3f3f3f3fusing 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);}}


0 0
原创粉丝点击