当前位置: 首页 > article >正文

【题解】CF2033G

题目

CF2033G
在这里插入图片描述

分析

  一道很显然是树形dp的题,但非常恶心QwQ。
  先不管复杂度,找找递推关系,一种很直接的想法如下(我觉得是错误的):

d p [ i ] [ k ] = m a x ( d p [ f a i ] [ k − 1 ] , d p [ s o n i , j [ k ] + 1 ) dp[i][k] = max(dp[fa_{i}][k-1], dp[son_{i,j}[k]+1) dp[i][k]=max(dp[fai][k1],dp[soni,j[k]+1)
其中 d p [ i ] [ k ] dp[i][k] dp[i][k]表示从 i i i开始,能量为 k k k的最远距离
f a i fa_{i} fai表示 i i i的根节点, s o n i , j son_{i,j} soni,j表示 i i i的第 j j j个子节点

  这样的问题是会计入这样的路线,实际距离为2,算成了4:
在这里插入图片描述

  所以,我们得把向上和向下两种情况分开记录:

d p 1 [ i ] dp1[i] dp1[i]表示向下最远距离,由于向下不消耗能量,所以可以少一维
d p 2 [ i ] [ i d ] dp2[i][id] dp2[i][id]表示 i i i节点如果删掉第 i d id id条边后向下最远距离,注意空间限制, d p 2 dp2 dp2得用 v e c t o r vector vector存储, i d id id得另外先预处理好(链式前向星可能会好一点)
i d [ i ] id[i] id[i]表示边 ( i , f a i ) (i, fa_{i}) (i,fai) f a i fa_{i} fai v e c t o r vector vector中的下标
h [ i ] h[i] h[i]表示节点 i i i的深度,根节点深度为 1 1 1

  于是,得到答案的式子为:

A N S ( i , k ) = m a x ( d p 1 [ i ] , d p 2 [ j ] [ i d   f r o m    i ] + h [ i ] − h [ j ] ) ANS(i, k) = max(dp1[i], dp2[j][id \ from \ \ i] + h[i] - h[j]) ANS(i,k)=max(dp1[i],dp2[j][id from  i]+h[i]h[j])

  后面的部分看起来很复杂,实际上直接用 S T ST ST表维护即可

代码

#include<bits/stdc++.h>
#define N 200005
#define inf 1000000000
using namespace std;
int t, n, q, fa[N][21], h[N], dp1[N], st[N][21];
int id[N];  // 记录每个根边的id 
vector<int> G[N], dp2[N];   // 去掉边i后向下最远 
void cl() {
	for(int j=0;(1<<j) <= n;j++) {
		for(int i=1;i<=n;i++) {
			st[i][j] = -inf;
		}
	}
	for(int i=1;i<=n;i++) {
		id[i] = 0;
		dp1[i] = 0;
	}
	for(int i=1;i<=n;i++) {
		vector<int>().swap(G[i]);
		vector<int>().swap(dp2[i]);
	}
}
void init(int x, int pre) {
	for(int j=1;(1<<j) <= h[x];j++) fa[x][j] = fa[fa[x][j-1]][j-1];
	for(int i=0;i<G[x].size();i++) {
		int y = G[x][i];
		if(y == pre) continue;
		id[y] = i;
		h[y] = h[x] + 1;
		fa[y][0] = x;
		init(y, x);
	}
}
void dfs(int x, int pre) {
	dp1[x] = 0;    // dp1是最大,se是第二大
	int se = -inf; 
	for(int i=0;i<G[x].size();i++) {
		int y = G[x][i];
		if(y == pre) continue;
		dfs(y, x);
		if(dp1[y] + 1 >= dp1[x]) {
			se = dp1[x];
			dp1[x] = dp1[y] + 1;
		} else if(dp1[y] + 1 > se) {
			se = dp1[y] + 1;
		}
	}
	for(int i=0;i<G[x].size();i++) {
		int y = G[x][i];
		if(y == pre) {
			dp2[x].push_back(-inf);
			continue;
		}
		if(dp1[x] == dp1[y] + 1) dp2[x].push_back(se);
		else dp2[x].push_back(dp1[x]);
	}
}
void show() {
	cout<<"showing"<<endl;
	cout<<"id: "; for(int i=1;i<=n;i++) cout<<id[i]<<' '; cout<<endl;
	cout<<"h: "; for(int i=1;i<=n;i++) cout<<h[i]<<' '; cout<<endl;
	cout<<"dp1: ";for(int i=1;i<=n;i++) cout<<dp1[i]<<' ';cout<<endl;
	for(int i=1;i<=n;i++) {
		for(int j=0;j<G[i].size();j++) {
			if(G[i][j] == fa[i][0]) continue;
			printf("root %d, erase %d, dp2: %d\n", i, G[i][j], dp2[i][j]);
		}
	}
	for(int j=0;(1<<j) <= n; j++) {
		for(int i=1;i<=n;i++) {
			if((1<<j) <= h[i]) printf("st[%d][%d]: %d \n" ,i, j, st[i][j]);
		}
	}
	cout<<endl;
}
int main() {
	cin>>t;
	while(t--) {
		cin>>n;
		cl();
		for(int i=1;i<=n-1;i++) {
			int u, v; scanf("%d %d", &u, &v);
			G[u].push_back(v);
			G[v].push_back(u);
		} 
		h[1] = 1; id[1] = -1;
		init(1, 0);
		dfs(1, 0);
		for(int i=2;i<=n;i++)  st[i][0] = dp2[fa[i][0]][id[i]] - h[fa[i][0]]; 
		for(int j=1;(1<<j) <= n;j++) {
			for(int i=1;i<=n;i++) {
				if((1<<j) <= h[i]) st[i][j] = max(st[i][j-1], st[fa[i][j-1]][j-1]);
			}
		}
		// show();
		cin>>q;
		while(q--) {
			int v, k; scanf("%d %d", &v, &k);
			k = min(k, h[v]-1);
			int ans = dp1[v];
			int step = log2(k), now = v;
			for(int step=0;(1<<step) <= k; step++) {
				if(!(k & (1<<step))) continue;
				ans = max(ans, st[now][step] + h[v]);
				now = fa[now][step];
			}
			printf("%d ", ans);
		}
	}
} 

http://www.kler.cn/a/382334.html

相关文章:

  • 安宝特应用 | 美国OSHA扩展Vuzix AR眼镜应用,强化劳动安全与效率
  • 项目代码第6讲:UpdownController.cs;理解 工艺/工序 流程、机台信息;前端的“历史 警报/工艺 记录”
  • Java内存区域进一步详解
  • FFmpeg第二话:FFmpeg 主要结构体剖析
  • 深度学习的DataLoader是什么数据类型,为什么不可用来索引
  • 了解RPC
  • ThinkPHP腾讯云国际短信对接
  • W5100S-EVB-Pico2评估板介绍
  • 史上最全盘点:一文告诉你低代码(Low-Code)是什么?为什么要用?
  • 【青牛科技】GC8549替代LV8549/ONSEMI在摇头机、舞台灯、打印机和白色家电等产品上的应用分析
  • 100种算法【Python版】第48篇——计数排序
  • CNN在线识别手写中文
  • 小区搜索和SSB简介
  • Rust 异步编程实战
  • 总结:Vue2中双向绑定不生效的排查方法及原理
  • [云讷科技]DASA数字孪生机器人概念
  • 【5.8】指针算法-双指针验证回文串
  • 小语言模型介绍与LLM的比较
  • 【d63】【Java】【力扣】141.训练计划III
  • MFC,DLL界面库设计注意
  • 基于uniapp和java的电动车智能充电系统软件平台的设计
  • html checkbox和label 文字不对齐解决办法
  • 某华迪加现场大屏互动系统mobile.do.php任意文件上传
  • windows安装mysql
  • Android 依赖统一配置管理(Version Catalogs)
  • 学习党的二十大精神,推动科技创新和发展