LOJ#2330 榕树之心 树形dp
瞎扯
这个题和\(\mathsf{ISIJ2019 Au}\)神仙学弟\(\mathsf{\color{red}c}\mathsf{hangruinian2020}\)争辩了半个多小时。
概括一下就是《浅谈全球\(\mathsf{Top10}\)神仙对于一类图论问题的感性证明的瞎扯》。
所以这篇题解里将会讲一些特别细的内容,而不是"显然"。
题意简述
给你一棵有根树和一个动点,动点一开始位于根结点\(1\)。一开始这棵树只有根结点,每次可以在已有的结点上沿原树边向外扩展一个结点,并使动点沿着新结点的方向移动一个结点。
请求出每个结点在原树被完全扩展后,动点是否能停留在第\(i\)个结点。
做法
首先这个题一眼\(30pts\),考虑\(\mathsf{Subtask 3}\)的做法。
考虑每一个结点不同儿子子树的两次操作会相互抵消,显然移回当前节点的最优方案一定是剩下来自重儿子子树的结点,所以尽可能消除重儿子子树即可。
令\(f(u)\)为动点在以\(u\)为根的子树扩展结束后与\(u\)的距离,令\(v=son(u)\),我们想办法写出转移方程。
- 如果\(f(v)+1\leq size(u)-size(v)-1\),那么以\(v\)为根的子树将会被全部消完,\(f(u) = size(u) \bmod 2\)
- 否则,我们应该尽可能消去\(f(v)+1\),那么\(f(u)=f(v)+1-(size(u)-size(v)-1)\)。
考虑求所有点的可行性,在移到 \(u\) 时我们已经处理了 \(1\to u\) 的路径和路径上结点的一些子树,显然存在一种策略可以可以使子树相互消除,那么问题就转化成和\(\mathsf{Subtask 3}\)类似的问题,把 \(1\to u\) 的路径压缩起来当做新根即可。
考虑暴力合并是\(O\left(n^2 \right)\)的,需要优化时间复杂度。
发现父亲节点对于当前重儿子的贡献只有子树大小之和以及\(son(fa(u))\),所以可以直接合并。但是\(size(son(u))==size(son(fa(u)))\)时是不能合并的,所以维护次重儿子并起来就好了。
Code
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register int
#define db double
#define in inline
namespace fast_io
{
char buf[1<<12],*p1=buf,*p2=buf,sr[1<<23],z[23],nc;int C=-1,Z=0;
in char gc() {return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<12,stdin),p1==p2)?EOF:*p1++;}
in ll read()
{
ll x=0,y=1;while(nc=gc(),(nc<48||nc>57)&&nc!=-1)if(nc==45)y=-1;
x=nc-48;while(nc=gc(),47<nc&&nc<58)x=(x<<3)+(x<<1)+(nc^48);return x*y;
}
in db gf() {re a=read(),b=(nc!='.')?0:read(),c=ceil(log10(b));return (b?a+(db)b/pow(10,c):a);}
in int gs(char *s) {char c,*t=s;while(c=gc(),c<32);*s++=c;while(c=gc(),c>32)*s++=c;return s-t;}
in void ot() {fwrite(sr,1,C+1,stdout);C=-1;}
in void flush() {if(C>1<<22) ot();}
template <typename T>
in void write(T x,char t)
{
re y=0;if(x<0)y=1,x=-x;while(z[++Z]=x%10+48,x/=10);
if(y)z[++Z]='-';while(sr[++C]=z[Z],--Z);sr[++C]=t;flush();
}
in void write(char *s) {re l=strlen(s);for(re i=0;i<l;i++)sr[++C]=*s++;sr[++C]='\n';flush();}
};
using namespace fast_io;
const int N=1e6+5;
int type,t,n,f[N],ans[N],son[N],siz[N];
vector<int>g[N];
in void add(re x,re y) {g[x].push_back(y);g[y].push_back(x);}
void dfs1(re u,re fa)
{
siz[u]=1;
for(auto v:g[u]) if(v!=fa)
{
dfs1(v,u);siz[u]+=siz[v];
if(siz[v]>siz[son[u]]) son[u]=v;
}
if(!son[u]) return;
if(f[son[u]]+1<=siz[u]-siz[son[u]]-1) f[u]=(siz[u]-1)&1;
else f[u]=f[son[u]]+1-(siz[u]-siz[son[u]]-1);
}
void dfs2(re u,re fa,re pre,re sum)
{
re sson=0;
if(u>1)
{
re sz=siz[u]+sum,pos=0;
if(siz[son[u]]>siz[pre]) pos=son[u]; else pos=pre;
if(f[pos]+1<=sz-siz[pos]-1) ans[u]=((sz-1)&1);
else ans[u]=f[pos]+1-(sz-siz[pos]-1);
}
for(auto v:g[u]) if(v!=fa&&v!=son[u]&&siz[v]>siz[sson]) sson=v;
for(auto v:g[u]) if(v!=fa)
{
re nw=(v==son[u]?sson:son[u]),tmp=siz[nw]>siz[pre]?nw:pre;
dfs2(v,u,tmp,sum+siz[u]-siz[v]-1);
}
}
int main()
{
type=read();t=read();
while(t--)
{
re n=read();
for(re i=1;i<=n;i++) f[i]=son[i]=ans[i]=siz[i]=0,g[i].clear();
for(re i=1;i<n;i++) add(read(),read());
dfs1(1,0);ans[1]=f[1];dfs2(1,0,0,0);
if(type==3) write(!ans[1],'\n');
else
{
for(re i=1;i<=n;i++) sr[++C]=(!ans[i])?'1':'0';
sr[++C]='\n';
}
}
return ot(),0;
}
LOJ#2330 榕树之心 树形dp的更多相关文章
- [清华集训2017]榕树之心[树dp]
题意 题目链接 分析 首先解决 \(subtask3\) ,我们的策略就是进入子树,然后用其它子树来抵消,注意在子树内还可以抵消. 可以转化为此模型:有一个数列 \(a\) ,每次我们可以选定两个值 ...
- 2018.09.01 loj#2330. 「清华集训 2017」榕树之心(树形dp)
传送门 树形dp好题啊. 我们用w[i]" role="presentation" style="position: relative;">w[ ...
- [LOJ#2330]「清华集训 2017」榕树之心
[LOJ#2330]「清华集训 2017」榕树之心 试题描述 深秋.冷风吹散了最后一丝夏日的暑气,也吹落了榕树脚下灌木丛的叶子.相识数年的Evan和Lyra再次回到了小时候见面的茂盛榕树之下.小溪依旧 ...
- [loj#2566][BZOJ5333] [Sdoi2018]荣誉称号 树形dp
#2566. 「SDOI2018」荣誉称号 休闲游戏玩家小 Q 不仅在算法竞赛方面取得了优异的成绩,还在一款收集钻石的游戏中排名很高. 这款游戏一共有 n 种不同类别的钻石,编号依次为 1 到 n ...
- 树形DP习题
听闻noip要考树形DP,本蒟蒻万分惶恐,特刷一坨题目,以慰受惊之心. codevs 1486 /*和非常出名的"选课"是一个题*/ #include<cstdio> ...
- bzoj4455 & loj2091 [Zjoi2016]小星星 容斥原理+树形DP(+状压DP?)
题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=4455 https://loj.ac/problem/2091 题解 很不错的一道题.(不过在当 ...
- 树形DP 学习笔记
树形DP学习笔记 ps: 本文内容与蓝书一致 树的重心 概念: 一颗树中的一个节点其最大子树的节点树最小 解法:对与每个节点求他儿子的\(size\) ,上方子树的节点个数为\(n-size_u\) ...
- P5405-[CTS2019]氪金手游【树形dp,容斥,数学期望】
前言 话说在\(Loj\)下了个数据发现这题的名字叫\(fgo\) 正题 题目链接:https://www.luogu.com.cn/problem/P5405 题目大意 \(n\)张卡的权值为\(1 ...
- poj3417 LCA + 树形dp
Network Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 4478 Accepted: 1292 Descripti ...
随机推荐
- 【漏洞学习】HOST 头攻击漏洞
日期:2018-03-06 14:32:51 作者:Bay0net 0x01. 前言 在一般情况下,几个网站可能会放在同一个服务器上,或者几个 web 系统共享一个服务器,host 头来指定应该由哪个 ...
- Django 过滤器 、日期格式化、数学运算
Django 的模板中的数学运算前言 django模板只提供了加法的filter,没有提供专门的乘法和除法运算:django提供了widthratio的tag用来计算比率,可以变相用于乘法和除法的计算 ...
- Vue-3D-Model:用简单的方式来展示三维模型
为什么做这个组件 我经常听到前端朋友们抱怨,在网页上展示三维模型太麻烦了.但是这方面的需求又有很多,例如做房地产的需要展示户型.卖汽车的需要展示汽车模型等. 在网页上展示三维模型就只能用WebGL技术 ...
- 【css】子元素浮动到了父元素外,父元素没有随子元素自适应高度,如何解决?
正常情况 如果子元素没有设置浮动(float),父元素的高度会随着子元素高度的改变而改变的. 设置浮动以后 父元素的高度不会随着子元素的高度而变化. 例如:在一个ul中定义若干个li,并设置float ...
- IntelliJ IDEA 快捷键终极大全
自动代码 常用的有fori/sout/psvm+Tab即可生成循环.System.out.main方法等boilerplate样板代码 . 例如要输入for(User user : users)只需输 ...
- [转帖]Ubuntu 清理 历史命令
Ubuntu彻底清除history命令历史记录 https://blog.csdn.net/u013554213/article/details/84954062 centos 可以使用这个命令 清理 ...
- 全新一台node节点加入到集群中
目录 前言 对新节点做解析 方法一 hosts 文件解析 方法二 bind 解析 测试 分发密钥对 推送 CA 证书 flanneld 部署 推送flanneld二进制命令 推送flanneld秘钥 ...
- 树形dp相关
前言 1:与树或图的生成树相关的动态规划. 2:以每棵子树为子结构,在父亲节点合并,注意树具有天然的子结构.这是很优美的很利于dp的. 3:巧妙利用Bfs或Dfs序,可以优化问题,或得到好的解决方法. ...
- 【JZOJ 3910】Idiot 的间谍网络
题面: Description 作为一名高级特工,Idiot 苦心经营多年,终于在敌国建立起一张共有n 名特工的庞大间谍网络. 当然,出于保密性的要求,间谍网络中的每名特工最多只会有一名直接领导.现在 ...
- P2505 [HAOI2012]道路
传送门 统计每条边被最短路经过几次,点数不大,考虑计算以每个点为起点时对其他边的贡献 对于某个点 $S$ 为起点的贡献,首先跑一遍最短路,建出最短路的 $DAG$ 考虑 $DAG$ 上的某条边被以 $ ...