前言

感觉是非常优秀的题目,写一篇题解记录一下。

HDU-7458 旅行(on Vjudge)

题面

题目描述

有一棵 \(n\) 个结点的无根树,每个结点都有对应的类型 \(c_i\) 和权重 \(w_i\) ,你需要在这棵树上规划若干次旅行。

对于一次旅行,你将从一个树上的一个结点出发,沿着树上的边进行旅行,最终到达另一个和起点类型相同的结点。

你会进行很多次旅行,但你希望对于每个结点,在所有旅行路线中最多只会经过一次。

一次旅行的价值是起始点和终止点的权重和,你需要规划旅行的方案使得旅行的总权重和最大。

输入格式

第一行输入一个正整数 \(t\ (1\le t\le 3)\) 代表数据组数。

对于每组数据:

第一行输入一个正整数 \(n\ (1\le n \le 2\times 10^5)\),代表树的点数。

第二行输入 \(n\) 个正整数 \(c_i\ (1\le c_i \le n)\) ,代表每个结点的类型。

第三行输入 \(n\) 个正整数 \(w_i\ (1\le w_i \le n)\) ,代表每个结点的权重。

接下来 \(n-1\) 行每行两个正整数 \(u_i,v_i\ (1\le u_i,v_i\le n,u_i\neq v_i)\) ,代表树上一条边,输入保证是一棵树。

输出格式

输出一行一个正整数代表答案。

输入输出样例

输入 #1

1
7
3 1 1 2 2 2 3
2 4 1 5 4 6 2
1 2
1 3
2 4
2 5
3 6
3 7

输出 #1

13

Hint

一种最优的旅行方案为:

旅行路线1:\(4\to 2\to 5\) ,价值为 \(9\)。

旅行路线2:\(1\to 3\to 7\),价值为 \(4\)。

价值总和为 \(13\)。

题解

我把本题的限制看成了恰好每个点经过一遍,于是浪费了一个晚上,在此警示后人。

注意到如果根节点走过或没走过状态确定,可以划分到每棵子树,考虑是树形 DP。设状态 \(f_{x,0}\) 表示子树 \(x\) 内 \(x\) 未走过的最大权值, \(f_{x,1}\) 表示子树 \(x\) 内 \(x\) 已走过的最大权值。\(f_{x,0}\) 的转移时容易的,因为不可能出现跨子树合并的贡献。

\[f_{x,0}=\sum_{v\in \operatorname{son}(x)}\max\{f_{x,0},f_{x,1}\}
\]

接下来我们考虑 \(f_{x,1}\),显然我们需要在子树 \(x\) 内寻找一个与 \(x\) 类型相同的点,然后合并。或者找到两个不同子树类型相同的点,合并顺便经过 \(x\)。考虑选择 \(y\) 作为合并的节点之一的贡献。设 \(x\to y\) 路径上的点为 \(a_1=x,a_2,\dots a_{k-1},a_k=y\),则可以算出贡献为下面式子。

\[w_x+w_y+f_{y,0}+\sum_{i=1}^{k-1}f_{a_i,0}-\max\{f_{a_{i+1},0},f_{a_{i+1},1}\}
\]

这个式子没有对齐,并不方便计算,于是我们稍微修改一下求和顺序,把下标对齐。

\[w_x+f_{x,0}+w_y+\sum_{i=2}^{k}f_{a_i,0}-\max\{f_{a_{i},0},f_{a_{i},1}\}
\]

选择两颗颜色相同的子树合并,就是 \(x\) 到这两个点的路径的贡献减去 \(f_{x,0}\),因为每一棵子树都恰好被按照 \(f_{x,0}\) 的方式多算了一次,直接减掉即可。代码中化简了这个式子。

注意到 \(w_x+f_{x,0}\) 是确定的,对于某种颜色的转移其实只需要使 \(w_y+\sum_{i=2}^{k}f_{a_i,0}-\max\{f_{a_{i},0},f_{a_{i},1}\}\) 最大。我们不妨把某棵子树某种颜色的最大值的集合存进一个 map。注意到这个式子只与 \(x\to y\) 的路径有关,在搜索回溯的时候加入当前节点,并对这个子树已有状态的集合使用懒标记增加逐步自底向上求出。我们还要支持合并两个集合,因为我们要合并多个子树的信息。

注意到这个合并可以使用启发式合并,对于每种颜色,选择最大的两个合并或选择根合并,顺便更新最大值的集合,就可以求出 \(f_{i,1}\)。时间复杂度 \(O(n\log^2 n)\)。

代码

顺便积累一个写法,C++17 以后,可以利用下列方式访问 map 中所有元素。(\([c,p]\) 中 \(c\) 为下标,\(p\) 为元素值)

for(auto [c,p]:g[b[v]])
#include <bits/stdc++.h>
using namespace std;
struct edge
{
long long v,nxt;
}e[600000];
long long t,n,u,v,h[300000],b[300000],c[300000],w[300000],f[300000][2],mx[300000],tg[300000],cnt=0;
map<long long,long long>g[300000];
inline long long read()
{
long long x=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
return x*f;
} void add_edge(long long u,long long v)
{
e[++cnt].nxt=h[u];
e[cnt].v=v;
h[u]=cnt;
} void dsu(long long x,long long fa)
{
f[x][0]=f[x][1]=mx[x]=0;
for(int i=h[x];i;i=e[i].nxt)
if(e[i].v!=fa)dsu(e[i].v,x),f[x][0]+=mx[e[i].v];
for(int i=h[x];i;i=e[i].nxt)
if(e[i].v!=fa)
{
long long v=e[i].v;
if(g[b[v]].count(c[x]))f[x][1]=max(f[x][1],g[b[v]][c[x]]+tg[b[v]]+f[x][0]+w[x]);
if(g[b[v]].size()>g[b[x]].size())swap(b[v],b[x]);
for(auto [c,p]:g[b[v]])
if(g[b[x]].count(c))f[x][1]=max(f[x][1],p+tg[b[v]]+g[b[x]][c]+tg[b[x]]+f[x][0]);
for(auto [c,p]:g[b[v]])
if(g[b[x]].count(c))g[b[x]][c]=max(g[b[x]][c],p+tg[b[v]]-tg[b[x]]);
else g[b[x]][c]=p+tg[b[v]]-tg[b[x]];
}
if(g[b[x]].count(c[x]))g[b[x]][c[x]]=max(g[b[x]][c[x]],w[x]-tg[b[x]]);
else g[b[x]][c[x]]=w[x]-tg[b[x]];
mx[x]=max(f[x][0],f[x][1]),tg[b[x]]+=f[x][0]-mx[x];
} int main()
{
t=read();
while(t--)
{
n=read();
for(int i=1;i<=n;i++)h[i]=tg[i]=cnt=0,b[i]=i,g[i].clear();
for(int i=1;i<=n;i++)c[i]=read();
for(int i=1;i<=n;i++)w[i]=read();
for(int i=1;i<=n-1;i++)u=read(),v=read(),add_edge(u,v),add_edge(v,u);
dsu(1,0);
printf("%lld\n",mx[1]);
}
return 0;
}

HDU7458 旅行 题解的更多相关文章

  1. noip2012开车旅行 题解

    题目大意: 给出n个排成一行的城市,每个城市有一个不同的海拔.定义两个城市间的距离等于他们的高度差的绝对值,且绝对值相等的时候海拔低的距离近.有两个人轮流开车,从左往右走.A每次都选最近的,B每次都选 ...

  2. 洛谷 P5022 旅行——题解

    发现大部分题解都是O(n^2)的复杂度,这里分享一个O(n)复杂度的方法. 题目传送 首先前60%的情况,图是一棵无根树,只要从1开始DFS,每次贪心走点的编号最小的点就行了.(为什么?因为当走到一个 ...

  3. [HAOI2006]旅行 题解(kruskal)

    [HAOI2006]旅行 Description Z小镇是一个景色宜人的地方,吸引来自各地的观光客来此旅游观光.Z小镇附近共有N个景点(编号为1,2,3,-,N),这些景点被M条道路连接着,所有道路都 ...

  4. NOIP 2018旅行题解

    从佳木斯回来刷一刷去年没A的题 题目描述 小 Y 是一个爱好旅行的 OIer.她来到 X 国,打算将各个城市都玩一遍. 小Y了解到, X国的 nn 个城市之间有 mm 条双向道路.每条双向道路连接两个 ...

  5. luoguP1081 开车旅行 题解(NOIP2012)

    这道题是真滴火!(一晚上加一节信息课!) 先链接一下题目:luoguP1081 开车旅行 首先,这个预处理就极其变态,要与处理出每一个点往后走A会去哪里,B会去哪里.而且还必须O(nlogn)给它跑出 ...

  6. [Sdoi2014]旅行 题解

    题目大意: 给出一个n个点的数,和m次操作.每个点有颜色和权值. 每次操作分4种 1:修改一个点的颜色 2:修改一个点的权值 3:询问从x到y的路径上,和x相同颜色的点的权值和(保证x,y同颜色) 4 ...

  7. 洛谷P5022 旅行 题解

    前面几个代码都是部分分代码,最后一个才是AC了的,所以最后一个有详细注释 安利一发自己的Blog 这是提高组真题,233有点欧拉回路的感觉. 题目大意: 一个 连通 图,双向边 ,无重边 , 访问图中 ...

  8. 洛谷P3313 [SDOI2014]旅行 题解 树链剖分+线段树动态开点

    题目链接:https://www.luogu.org/problem/P3313 这道题目就是树链剖分+线段树动态开点. 然后做这道题目之前我们先来看一道不考虑树链剖分之后完全相同的线段树动态开点的题 ...

  9. 洛谷P5022 旅行 题解 去环/搜索

    题目链接:https://www.luogu.org/problem/P5022 这道题目一开始看的时候没有思路,但是看到数据范围里面有一个: \(m = n-1\) 或 \(m = n\) ,一下子 ...

  10. luogu P4842 城市旅行

    嘟嘟嘟 好题,好题 刚开始突发奇想写了一个\(O(n ^ 2)\)暴力,结果竟然过了?!后来才知道是上传题的人把单个数据点开成了10s-- 不过不得不说我这暴力写的挺好看的.删边模仿链表删边,加边的时 ...

随机推荐

  1. STLINK/JLINK USB识别不稳定问题的解决

    第一阶段:自己基于STM32F103C8T6的STLINK,调试一直正常. 第二阶段:发现了硬汉的教程,基于JLINK的RTT viewer 代替串口打印调试信息,所以购买了JLINK,手里的STLI ...

  2. QT 可绑定属性 QProperty QObjectBindableProperty QObjectComputedProperty,简化信号、槽(SIGNAL、SLOT)机制的方法

    QT提供的可绑定属性是指这些属性可以绑定到其他值或表达式上(通常是 C++ lambda 表达式).如果属性是通过表达式进行绑定,该属性会跟随表达式自动更新.可绑定属性由 QProperty 类和 Q ...

  3. redis的作用:高性能和高并发

    一.高性能 假设这么个场景,你有个操作,一个请求过来,吭哧吭哧你各种乱七八糟操作mysql,半天查出来一个结果,耗时600ms.但是这个结果可能接下来几个小时都不会变了,或者变了也可以不用立即反馈给用 ...

  4. jdbc写一个访问数据库的工具类

    操作的工具类 package com.zjw.jdbc2; /** * jdbc操作的工具类 * @author Administrator * */ import java.sql.Connecti ...

  5. 【HUST】代数学|理想的分解习题

    以下内容中,背景知识部分尽数由GPT生成,生成的方式是直接对问题进行提问,存在错误的小节我已经标注,不保证不存在其他错误. 习题部分是GPT生成后,我将看不懂的地方自己重写了一遍的结果.不保证完全正确 ...

  6. 【ROS】1.1 ROS基本命令介绍

    原视频 ROS基本命令 右键新标签页查看大图! have to do Command Command Result 中文解释 图示 roscore Open the core of the ROS. ...

  7. Centos 7 关于防火墙的命令

    有些人安装的linux的系统默认防火墙不是iptables,而是firewall,那就得使用以下方式关闭防火墙了. >>>关闭防火墙 systemctl stop firewalld ...

  8. Python3 + selenium 获取疫情中高风险区数据

    背景: 需要动态将疫情风险区数据和区域业务动作想结合, 赋能销售业务, 内部使用非商用哈 环境: Python3 + selenium 自动化测试软件中 Chrome 驱动 exe 文件 输出: 以 ...

  9. 内网服务器离线安装部署 Ollama

    一.安装 Ollama 1.官网下载地址:Releases · ollama/ollama 2.cd至下载目录 3.执行二进制文件安装 sudo tar -C /usr -xzf ollama-lin ...

  10. rancher 卸载后重装报错

    报错信息 kubectl create namespace cattle-system Error from server (InternalError): Internal error occurr ...