小奇的仓库(树形DP)
「题目背景」
小奇采的矿实在太多了,它准备在喵星系建个矿石仓库。令它无语的是,喵星系的货运飞船引擎还停留在上元时代!
「问题描述」
喵星系有n个星球,星球以及星球间的航线形成一棵树。
从星球a到星球b要花费[dis(a,b) Xor M]秒。(dis(a,b)表示ab间的航线长度,Xor为位运算中的异或)
为了给仓库选址,小奇想知道,星球i(1<=i<=n)到其它所有星球花费的时间之和。
「输入格式」
第一行包含两个正整数n,M。
接下来n-1行,每行3个正整数a,b,c,表示a,b之间的航线长度为c。
「输出格式」
n行,每行一个整数,表示星球i到其它所有星球花费的时间之和。
「样例输入」
4 0
1 2 1
1 3 2
1 4 3
「样例输出」
6
8
10
12
「数据范围」
序号 N M
1 6 0
2 100 5
3 2000 9
4 50000 0
5 50000 0
6 50000 1
7 50000 6
8 100000 10
9 100000 13
10 100000 15
保证答案不超过2*10^9
下面一段话是出题人神秘而不失优雅的题解
算法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么~~
下面是自己的话:
既然是棵树,又要快速地求每个点的值,那一定是树形DP加上换根的操作啦~
但是异或m要怎么处理呢?可以观察数据规模,发现m最大最大也就15,换成二进制数也就是 1111,所以发现异或m最多只会对数字的后面4位造成影响(异或0甚至无法造成什么影响)
于是愉快地写出DP数组 f[i]和sz[i][0~15]
f表示此时以i为根的子树到i节点的距离之和(减去后缀后的和)
sz表示此时距离以j为后缀的共有几个
每一次向根节点方向转移时会加上一条边的长度,此时不同后缀距离的后缀会发生相应改变,然后更新父亲相应后缀的sz值。
然后f里统计的距离总和是抹掉所有后缀后的总和,即不考虑后缀的贡献。如有一个距离是 10111(2),抹去长度为2的后缀后就只剩下10100,然后将这个结果加到f数组里,到最后根节点统计最终答案时再考虑每个后缀的贡献,此时的sz数组就派上用场了(具体看代码)
还有一点,就是最后要把答案减去m,因为统计后缀贡献时,多加了自己到自己的距离(本来为0,xor m 后变成了m)。
代码如下
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm> #define For(i,a,b) for(register int i=a;i<=b;++i)
#define Re register
#define Pn putchar('\n')
#define inf 0x7f7f7f
#define llg long long
using namespace std;
const int N=1e5+;
int sz[N][];
int head[N],nxt[N*],v[N*],cnt=;
llg w[N*],z,fn[N],f[N];
int n,m,x,y,ct,tot; inline void read(int &v){
v=;
char c=getchar();
while(c<''||c>'')c=getchar();
while(c>=''&&c<='')v=v*+c-'',c=getchar();
}
inline void read(llg &v){
v=;
char c=getchar();
while(c<''||c>'')c=getchar();
while(c>=''&&c<='')v=v*+c-'',c=getchar();
}
void write(llg x){
if(x>)write(x/);
int xx=x%;
putchar(xx+'');
} void add(int ux,int vx,llg wx){
cnt++;
nxt[cnt]=head[ux]; head[ux]=cnt; v[cnt]=vx; w[cnt]=wx;
cnt++;
nxt[cnt]=head[vx]; head[vx]=cnt; v[cnt]=ux; w[cnt]=wx;
} void DFS1(int x,int fa){
sz[x][]=;
for(Re int i=head[x];i;i=nxt[i]){
int vv=v[i];
if(vv==fa)continue;
DFS1(vv,x);
f[x]+=f[vv];
For(j,,tot){
int Nsm=j+w[i];
int Nst=Nsm & ct;
sz[x][Nst]+=sz[vv][j];
f[x]+=sz[vv][j]*(Nsm-Nst);
}
}
}
int Bsz[N][];
void DFS2(int x,int fa){ //换根
fn[x]=f[x];
For(st,,tot){
fn[x]+=(st^m)*sz[x][st];
}
For(st,,tot)Bsz[x][st]=sz[x][st];
llg Bf=f[x]; for(Re int i=head[x];i;i=nxt[i]){
int vv=v[i];
if(vv==fa)continue; int Nsm,Nst; For(st,,tot){
Nsm =st+w[i];
Nst=Nsm&ct;
sz[x][Nst]-=sz[vv][st];
f[x]-=sz[vv][st]*(Nsm-Nst);
} f[vv]=f[x];
For(st,,tot){
Nsm=st+w[i];
Nst=Nsm&ct;
sz[vv][Nst]+=sz[x][st];
f[vv]+=sz[x][st]*(Nsm-Nst);
} DFS2(vv,x); f[x]=Bf;
For(st,,tot)sz[x][st]=Bsz[x][st];
}
} int main(){
// freopen("warehouse.in","r",stdin);
// freopen("warehouse.out","w",stdout);
read(n); read(m); if(m==)ct=,tot=;
if(m==)ct=,tot=;
if(m==)ct=,tot=;
if(m==)ct=,tot=;
if(m>=)ct=,tot=; //简单粗暴的预处理 For(i,,n-){
read(x); read(y); read(z);
add(x,y,z);
}
DFS1(,);
DFS2(,);
For(i,,n){
write(fn[i]-m); Pn;
}
return ;
}
小奇的仓库(树形DP)的更多相关文章
- [CSP-S模拟测试]:小奇的仓库(warehouse)(树形DP)
题目背景 小奇采的矿实在太多了,它准备在喵星系建个矿石仓库.令它无语的是,喵星系的货运飞船引擎还停留在上元时代! 题目描述 喵星系有$n$个星球,星球以及星球间的航线形成一棵树.从星球$a$到星球$b ...
- 【换根DP】小奇的仓库
题目背景 小奇采的矿实在太多了,它准备在喵星系建个矿石仓库.令它无语的是,喵星系的货运飞船引擎还停留在上元时代! 题目内容 喵星系有\(n\)个星球,星球以及星球间的航线形成一棵树. 从星球\(a\) ...
- BZOJ4446:[SCOI2015]小凸玩密室(树形DP)
Description 小凸和小方相约玩密室逃脱,这个密室是一棵有n个节点的完全二叉树,每个节点有一个灯泡.点亮所有灯泡即可逃出密室. 每个灯泡有个权值Ai,每条边也有个权值bi.点亮第1个灯泡不需要 ...
- 【bzoj4550】小奇的博弈 博弈论+dp
题目描述 这个游戏是在一个1*n的棋盘上进行的,棋盘上有k个棋子,一半是黑色,一半是白色.最左边是白色棋子,最右边 是黑色棋子,相邻的棋子颜色不同. 小奇可以移动白色棋子,提比可以移动黑色的棋子, ...
- [CSP-S模拟测试]:小奇挖矿2(DP+赛瓦维斯特定理)
题目背景 小奇飞船的钻头开启了无限耐久+精准采集模式!这次它要将原矿运到泛光之源的矿石交易市场,以便为飞船升级无限非概率引擎. 题目描述 现在有$m+1$个星球,从左到右标号为$0$到$n$,小奇最初 ...
- bzoj 5072 小A的树 —— 树形DP
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=5072 由于对于一个子树,固定有 j 个黑点,连通块大小是一个连续的范围: 所以记 f[i][ ...
- [IOI2008/BZOJ1791 岛屿](处理基环树的小技巧&基于bfs树形DP)
IOI2008/BZOJ1791 岛屿 题目大意是在一个基环树森林里求每一棵基环树的直径①的和. 其实就是树的直径的基环树升级版.我们先把环找出来,然后从环上的每一个节点x出发,并且不经过环上其他节点 ...
- LUOGU P4253 [SCOI2015]小凸玩密室(树形dp)
传送门 解题思路 玄学树形\(dp\),题目描述极其混乱...看错了两次题,设首先根据每次必须点完子树里的灯才能点别的,那么点灯情况只有两种,第一种是点到某一个祖先,第二种是点到某一个祖先的兄弟.所以 ...
- 小奇的仓库:换根dp
一道很好的换根dp题.考场上现场yy十分愉快 给定树,求每个点的到其它所有点的距离异或上m之后的值,n=100000,m<=16 只能线性复杂度求解,m又小得奇怪.或者带一个log像kx一样打一 ...
随机推荐
- Java基础知识查漏 一
Java基础知识查漏 一 Jdk和jre Jdk是java程序设计师的开发工具,只要包含编译程序,jvm和java函数库 Jre中只有jvm和java函数库,没有编译程序的相关工具,适合只运行不撰写j ...
- 图片转base64存储
图片转base64存储 base64.b64encode(r.content) url='http://www.heze.cn/info/themes/heze/Public/tel/?tel=MDU ...
- Jquery跨域调用
今天在项目中须要做远程数据载入并渲染页面,直到开发阶段才意识到ajax跨域请求的问题,隐约记得Jquery有提过一个ajax跨域请求的解决方式,于是即刻翻出Jquery的API出来研究,发现JQuer ...
- tomcat服务器配置java堆内存大小
我用的是绿色免安装的tomcat,找到tomcat下的bin文件夹下的catalina.bat文件: 编辑该文件,编辑参数,没有的话手动加上: set JAVA_OPTS=-server -Xms51 ...
- javascript 正则表达式 进阶教程
学习之前先来说一说一些概念 子项 1.正则的一个分组为一个子项,子项的匹配结果可以在这个子项之后被使用 2.子项是有顺序的,以(出现的位置顺序从左到右,第一个'()'--分组 包含的为第一子项,第二个 ...
- HashMap vs ConcurrentHashMap — 示例及Iterator探秘
如果你是一名Java开发人员,我能够确定你肯定知道ConcurrentModificationException,它是在使用迭代器遍历集合对象时修改集合对象造成的(并发修改)异常.实际上,Java的集 ...
- 我在面试.NET/C#程序员时会提出的问题
我在面试.NET/C#程序员时会提出的问题 2011-03-03 15:38 by 老赵, 28107 visits 说起来我也面试过相当数量的.NET(包括C#,后文不重复)程序员了,有的通过电话, ...
- 脚踏实地学C#5-扩展方法
扩展方法(Extension Method) MSDN定义:能够向现有类型“添加”方法,而无需创建新的派生类型.重新编译或以其他方式修改原始类型. 扩展方法须知: 1.扩展方法声明所在的类必须被声明为 ...
- H3C-交换机端口绑定
1.端口和MAC地址绑定: (1)使用am命令: [switch]am user-bind mac-address 00e0-fc23-f8d3 interface Ehternet 0/1 (2)使 ...
- BZOJ_2989_数列&&BZOJ_4170_极光_KDTree
BZOJ_2989_数列&&BZOJ_4170_极光_KDTree Description "若是万一琪露诺(俗称rhl)进行攻击,什么都好,冷静地回答她的问题来吸引她.对方 ...