树上点分治模板bzoj1468

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
struct edgee
{
	int from, to, cost;
	edgee(int f, int t, int c) :from(f), to(t), cost(c)
	{}
	edgee()
	{}
};
edgee edge[200000];
int first[100000], nextt[200000],edgetot,n,k;
int value[1000000];
void addedge(int from, int to, int cost)
{
	edge[edgetot] = edgee(from, to, cost);
	nextt[edgetot] = first[from];
	first[from] = edgetot++;
	edge[edgetot] = edgee(to, from, cost);
	nextt[edgetot] = first[to];
	first[to] = edgetot++;
}
int size[100000],msize[100000];
bool iscenter[100000];
int center;
void getsize(int now,int f,int total)
{
	size[now] = 1; msize[now] = -1;
	for (int i = first[now]; i != -1; i = nextt[i])
	{
		int to = edge[i].to;
		if (to == f||iscenter[to])continue;
		getsize(to, now, total);
		size[now] += size[to];
		msize[now] = max(msize[now], size[to]);
	}
	msize[now] = max(msize[now], total - size[now]);
	if (msize[now] < msize[center])center = now;
}
void getdpth(int num, int fa, int rvalue,int &tot)
{
	value[tot++] = rvalue; size[num] = 1;
	for (int i = first[num]; i != -1; i = nextt[i])
	{
		int to = edge[i].to;
		if (to == fa || iscenter[to])continue;
		getdpth(to, num, rvalue + edge[i].cost, tot);
		size[num] += size[to];
	}
}
int cal(int num,int rvalue)//这分两种一个是从center开始一个是从center的子节点开始,并且每次开始的时候size都是更新了的
{
	int tot = 0;
	getdpth(num, -1, rvalue, tot);
	sort(value, value + tot);
	int l, r; l = 0; r = tot-1;
	int ans = 0;
	while (l < r)
	{
		while (value[r] + value[l] <= k&&l<r)ans += r-l, l++;
		r--;
	}
	return ans;
}
int work(int s,int total,int fa)
{
	center = 0; msize[0] = 1000000000;
	getsize(s, -1, total);//这个时候就找centerl了;
	iscenter[center] = 1;
	int ans = 0;
	ans+=cal(center, 0);
	for (int i = first[center]; i != -1; i = nextt[i])
	{
		int to = edge[i].to;
		if (to == fa || iscenter[to])continue;
		ans -= cal(to, edge[i].cost);//这的时候重新优化了size
		ans += work(to, size[to],center);//这我先开始写错了。。。。注意fa是center而不是s
	}
	return  ans;
}
int main()
{
	scanf("%d", &n);
	for (int i = 0; i <= n; i++)first[i] = -1;
	for (int i = 1; i < n; i++)
	{
		int a, b, c;
		scanf("%d%d%d", &a, &b, &c);
		//cout << "I:" << i << " " << "a:" << a << " " << "b:" << b << " " << "c:" << c << endl;
		addedge(a, b, c);
	}
	scanf("%d", &k);
	int ans = 0;
	if(n)ans=work(1, n, -1);
	printf("%d\n", ans);
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值