P4149 [IOI2011]Race dsu on tree

这题据说是点分治,但是看到有大佬说dus on tree可以写出来,就试了试。。。

https://www.luogu.com.cn/problem/P4149

这个题让我再一次认识了树上启发式合并,谢谢,具体看代码就好

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<map>
#include<vector>
using namespace std;
const int maxn = 2e5 + 1010;
typedef long long ll;
int k;
map<ll,ll>ins;
int n;

struct Node {
	int p;
	ll len;
	Node(int _p,ll _len):p(_p),len(_len) {}
};



vector<Node>G[maxn];
void add(int be, int en,ll len) {
	G[be].push_back(Node(en,len));
}


int siz[maxn];
int son[maxn];
ll dep[maxn];
ll dis[maxn];

int dfs(int x, int fa,ll d,ll dd) {
	siz[x] = 1;
	dis[x] = dd;
	dep[x] = d;
	
	int c = 0;
	for (int i=0; i<G[x].size(); i++) {
		int p = G[x][i].p;
		ll len = G[x][i].len;
		if (p == fa) continue;
		dfs(p, x,d+1,dd+len);

		siz[x] += siz[p];
		if (siz[p] > c) {
			c = siz[p];
			son[x] = p;
		}
	}
	return 0;
}
ll cns = 0;
ll ans;


int cal(int root,int x, int fa) {
	

	ll ln = k+2*dis[root] - dis[x];
	
	if(ins[ln]) {
		ans = min(ans,dep[x] + ins[ln] - 2LL*dep[root]);
	}
	
	for (int i=0; i<G[x].size(); i++) {
		int p = G[x][i].p;
		ll len = G[x][i].len;
		if (p == fa) continue;
		cal(root,p, x);
	}
	return 0;
}
int cal2(int x, int fa) {
	if(ins[dis[x]] == 0){
		ins[dis[x]] = dep[x];
	} 
	else{
		ins[dis[x]] = min(ins[dis[x]],dep[x]);
	}
	if(dis[x] == k) {
		ans = min(ans,dep[x]-1);
	}
	
	for (int i=0; i<G[x].size(); i++) {
		int p = G[x][i].p;
		ll len = G[x][i].len;
		if (p == fa) continue;
		cal2(p, x);
	}
	return 0;
}

int dfs2(int x, int fa, int flag) {
	for (int i=0; i<G[x].size(); i++) { //先算轻儿子
		int p = G[x][i].p;
		ll len = G[x][i].len;
		if (p == fa) continue;
		if (p == son[x]) continue;
		dfs2(p, x, 0);
	}

	if (son[x] != 0) {//单独算重儿子
		dfs2(son[x], x, 1);
	}
	
	
	
	ll ln = k+dis[x] ;
	
	if(ins[ln]) {
		ans = min(ans,dep[x] + ins[ln] - 2LL*dep[x]);
	}
	
	if(ins[dis[x]] == 0) ins[dis[x]] = dep[x];
	
	for(int i=0;i<G[x].size();i++){
		int p = G[x][i].p;
		if(p == fa || p == son[x]) continue;
		cal(x,p,x);
		cal2(p,x);
	}
	
	if (flag == 0) {//删除答案
		ins.clear();
	}
	return 0;
}



int main() {
////
//	freopen("in.txt", "r", stdin);
//	freopen("out.txt", "w", stdout);

	int be;
	scanf("%d %d", &n,&k);
	int x,y;
	ll len;
	ans = 1e17;
	for (int i = 2; i <= n; i++) {
		scanf("%d %d %lld",&x,&y,&len);
		x++,y++;
		add(x,y,len);
		add(y,x,len);
	}
	dfs(1, -1,1,0);
	dfs2(1, -1, 0);

	if(ans == 1e17) ans = -1;

	printf("%lld
",ans);

	return 0;
}

  

寻找真正的热爱
原文地址:https://www.cnblogs.com/lesning/p/13786069.html