【换根DP】小奇的仓库
题目背景
小奇采的矿实在太多了,它准备在喵星系建个矿石仓库。令它无语的是,喵星系的货运飞船引擎还停留在上元时代!
题目内容
喵星系有\(n\)个星球,星球以及星球间的航线形成一棵树。
从星球\(a\)到星球\(b\)要花费\([\text{dis}(a,b)\ \text{xor}\ M]\)秒。(\(\text{dis}(a,b)\)表示ab间的航线长度,\(\text{xor}\)为位运算中的异或)
为了给仓库选址,小奇想知道,星球\(i(1\leq i\leq n)\)到其它所有星球花费的时间之和。
数据范围
\(6\leq n\leq 100000,0\leq M\leq 15\)
思路
出题人:
算法1:
不会写函数的小伙伴们,我们只需要写个floyd,就有10分啦!
算法2:
在算法1的基础上,我们对每条边处理一下xor,就有20分啦!
算法3:
简单的树形DP,或者你会nlogn的dij,处理完每个点到其它点的最短路后再加上xor,那么这样就有30分啦!
算法4:
第4、5个点无需xor,那么我们树形DP扫一个节点与其它所有节点的路径长度之和,可以合并信息,最终均摊O(1),50分到手。
算法5:
第6个点xor 1,那么我们树形DP到一个点时记录有多少个0,多少个1,然后每当一条路径到2,那部分就再记录一个值,60分到手。
算法6:
如果你第6个点都过了,却没有满分,笨死啦!
一样的嘛,就是原来的“0”、“1”、大于等于2变成了0~16么~~
满了。
我:?
考场上直接打的\(O(n^2)\)枚举区间再加上求\(\text{LCA}\)的复杂度的暴力,结果一时脑瘫建边的时候就异或了\(M\)结果惨挂\(10pts\),然后考后改成最后再异或就\(30pts\)了...(差点有比郭神高的机会呢qwq)
然后正解是换根\(dp\),又是假期埋下的一个坑吗
先考虑没有异或的情况。设已经搜到了边\(<u,v,w>\),且\(u\)是\(v\)的父亲,那么如何更新\(ans[v]\)呢?
\]
当然你会选择合并同类项,不过先不合并比较好理解,对于\(u\)以上的节点,其个数为\(n-size[v]\),对于原来的\(ans[u]\)距离多了一个\(w\),所以加上\((n-size[v])\times w\),对于\(v\)的子树节点,对\(v\)的距离就是其到\(u\)的距离减去\(w\),所以就能得到以上的柿子。
大概这个样子:

然而本题要求异或,由我惨挂10分的经历可以知道异或并不满足分配律,所以并不能边加边异或。然而可以看出\(M\leq 15\),转换为二进制为\(1111\),所以最后异或\(M\)的时候仅会对后四位有影响,所以只需要记录后四位的状态即可。
设\(f[i][j]\)表示到了\(i\)点,当前后四位的状态为\(j\),能伸展出的路径条数。
对于初始:\(f[u][0]=1\),表示自己到自己为一条路径。为了方便,你可以先加上自己然后最后减去。
然后就是\(f[u][(j+w)\ \%\ 16]+=f[v][j]\),从子树转移过来。
然而除了子树以外还有别的点,如何转移呢?
\]
很容易理解,对于\(v\)的父亲\(u\),先刨去子树\(v\)的贡献,然后剩下的就是其他点到\(u\)的贡献,你再通过\(<u,v,w>\)边转移到\(v\)上,再加上原来就有的\(v\)的子树的,就是整棵树到\(v\)的贡献。
最后你再异或个\(M\)即可。
代码
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
int n,M;
long long f[maxn][20],ans[maxn],a[20];
struct Edge{
int from,to,w,nxt;
}e[maxn<<1];
inline int read(){
int x=0,fopt=1;
char ch=getchar();
while(!isdigit(ch)){
if(ch=='-')fopt=-1;
ch=getchar();
}
while(isdigit(ch)){
x=(x<<3)+(x<<1)+ch-48;
ch=getchar();
}
return x*fopt;
}
int head[maxn],cnt;
inline void add(int u,int v,int w){
e[++cnt].from=u;
e[cnt].to=v;
e[cnt].w=w;
e[cnt].nxt=head[u];
head[u]=cnt;
}
void dfs1(int u,int fa){
f[u][0]=1;
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to;
if(v==fa)continue;
dfs1(v,u);
ans[u]+=ans[v];
for(int j=0;j<=15;j++){
int w=e[i].w;
f[u][(j+w)%16]+=f[v][j];
ans[u]+=f[v][j]*w;
}
}
}
void dfs2(int u,int fa){
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to,w=e[i].w;
if(v==fa)continue;
memset(a,0,sizeof(a));//临时先开个数组存一下,因为下面还要加siz,最好不要直接更新
int siz=0;
for(int j=0;j<=15;j++){
a[(j+w)%16]+=f[u][j]-f[v][((j-w)%16+16)%16];//防止下标变负
siz+=f[v][j];
}
ans[v]=ans[u]+(n-2*siz)*w;
for(int j=0;j<=15;j++)
f[v][j]+=a[j];
dfs2(v,u);
}
}
int main(){
freopen("B.in","r",stdin);
freopen("B.out","w",stdout);
n=read();M=read();
for(int i=1;i<n;i++){
int u=read(),v=read(),w=read();
add(u,v,w);
add(v,u,w);
}
dfs1(1,0);
dfs2(1,0);
for(int i=1;i<=n;i++){
f[i][0]--;//刨去到自己的路径
for(int j=0;j<=15;j++)
ans[i]+=((j^M)-j)*f[i][j];//加上异或后相差的值,另外还是老问题异或的优先级
printf("%lld\n",ans[i]);
}
return 0;
}
【换根DP】小奇的仓库的更多相关文章
- 小奇的仓库:换根dp
一道很好的换根dp题.考场上现场yy十分愉快 给定树,求每个点的到其它所有点的距离异或上m之后的值,n=100000,m<=16 只能线性复杂度求解,m又小得奇怪.或者带一个log像kx一样打一 ...
- 换根DP+树的直径【洛谷P3761】 [TJOI2017]城市
P3761 [TJOI2017]城市 题目描述 从加里敦大学城市规划专业毕业的小明来到了一个地区城市规划局工作.这个地区一共有ri座城市,<-1条高速公路,保证了任意两运城市之间都可以通过高速公 ...
- 洛谷 P4284 [SHOI2014]概率充电器 概率与期望+换根DP
洛谷 P4284 [SHOI2014]概率充电器 概率与期望+换根DP 题目描述 著名的电子产品品牌\(SHOI\) 刚刚发布了引领世界潮流的下一代电子产品-- 概率充电器: "采用全新纳米 ...
- [BZOJ4379][POI2015]Modernizacja autostrady[树的直径+换根dp]
题意 给定一棵 \(n\) 个节点的树,可以断掉一条边再连接任意两个点,询问新构成的树的直径的最小和最大值. \(n\leq 5\times 10^5\) . 分析 记断掉一条边之后两棵树的直径为 \ ...
- 2018.10.15 NOIP训练 水流成河(换根dp)
传送门 换根dp入门题. 貌似李煜东的书上讲过? 不记得了. 先推出以1为根时的答案. 然后考虑向儿子转移. 我们记f[p]f[p]f[p]表示原树中以ppp为根的子树的答案. g[p]g[p]g[p ...
- 国家集训队 Crash 的文明世界(第二类斯特林数+换根dp)
题意 题目链接:https://www.luogu.org/problem/P4827 给定一棵 \(n\) 个节点的树和一个常数 \(k\) ,对于树上的每一个节点 \(i\) ,求出 \( ...
- Acesrc and Travel(2019年杭电多校第八场06+HDU6662+换根dp)
题目链接 传送门 题意 两个绝顶聪明的人在树上玩博弈,规则是轮流选择下一个要到达的点,每达到一个点时,先手和后手分别获得\(a_i,b_i\)(到达这个点时两个人都会获得)的权值,已经经过的点无法再次 ...
- bzoj 3566: [SHOI2014]概率充电器 数学期望+换根dp
题意:给定一颗树,树上每个点通电概率为 $q[i]$%,每条边通电的概率为 $p[i]$%,求期望充入电的点的个数. 期望在任何时候都具有线性性,所以可以分别求每个点通电的概率(这种情况下期望=概率 ...
- codeforces1156D 0-1-Tree 换根dp
题目传送门 题意: 给定一棵n个点的边权为0或1的树,一条合法的路径(x,y)(x≠y)满足,从x走到y,一旦经过边权为1的边,就不能再经过边权为0的边,求有多少边满足条件? 思路: 首先,这道题也可 ...
随机推荐
- 购书网站前端实现(HTML+CSS+JavaScript)
购书+阅读静态网页设计与实现 一.主页设计HTML 1.效果展示及实现 2.完整代码 二.主页样式布局CSS 三.空间功能实现Javascript 主要功能 Javascript完整代码: 总结 购书 ...
- Java反射库介绍
本文主要罗列了Java反射中使用比较多的一些方法,主要都是来自 java.lang.reflect包下的Field.Method 和 Constructor 等三个类,希望对大家有帮助!! 介绍 ja ...
- Druid连接池配置全攻略
Druid是阿里开源出来的数据库连接池,性能非常好,还自带日志监控. 它的DataSource类为:com.alibaba.druid.pool.DruidDataSource. 由于使用的yaml格 ...
- Java垃圾回收System.gc()的理解
System.gc()无法保证GC一定执行 在默认情况下,通过System.gc()或者Runtime.getRuntime().gc()的调用,会显式触发Full GC,同时对老年代和新生代进行回收 ...
- SSO单点登录可以自己实现吗?--开源软件诞生10
ERP与SSO的恩怨情仇--第10篇 用日志记录“开源软件”的诞生 赤龙 ERP 开源地址: 点亮星标,感谢支持,与开发者交流 kzca2000 码云:https://gitee.com/redrag ...
- C语言汇总3
16-18 1.常量 整型常量:1: 2: 3: 实型常量(小数):单精度常量[3.14],双精度常量(默认情况下)[10.1f] 字符型常量 ' 5 ',只要在双引号的任意的唯一一个字符就为字符型常 ...
- Vue入门到精通
Vue.js - Day1 课程介绍 前5天: 都在学习Vue基本的语法和概念:打包工具 Webpack , Gulp 后5天: 以项目驱动教学: 什么是Vue.js Vue.js 是目前最火的一个前 ...
- Jakartase_IO流_ — Commons IO_(IO流终极篇)
一.前言 Apache Commons IO是Apache基金会创建并维护的Java函数库. 它提供了许多类使得开发者的常见任务变得简单,同时减少重复代码 二.Commons IO 类库 2.1 Fi ...
- 容器云平台No.5~企业级私有镜像仓库Harbor V2.02
镜像仓库 仓库,顾名思义,就是存放东西的地方,Docker仓库,理所当然,就是存放docker镜像的地方了. Docker仓库分公有仓库和私有仓库.共有仓库有hub.docker.com.gcr.io ...
- vue学习06 v-show指令
目录 vue学习06 v-show指令 v-show指令是:根据真假切换元素的显示状态 原理是修改元素的display,实现显示隐藏 指令后面的内容,最终都会解析为布尔值(true和false) 练习 ...