[USACO10FEB]慢下来Slowing down
线段树 树的dfs序
来自 洛谷 P1982 的翻译
by GeneralLiu
来自 jzyz 的翻译 %mzx

线段树 dfs序
数据结构的应用
“数据结构 是先有需求 再有应用” by mzx
那么按照这个思路
先看看针对这道题 有什么需求
再考虑用什么数据结构去解决
以及怎么用该数据结构
这是一个树上的题
某个人进了寝室
只会影响到他子树的答案
因为只有他的 子树 回寝室时
要经过他 得slowing down对吧
这时 要对他的 子树的答案全部 区间+1
这是 对dfs序的需求
需要 dfs序 将树转换成区间
区间修改 单点查询 又是对 线段树 的需求
需要 线段树 的高效维护
如有dalao有更高效的方法请博客留言
我目前只学了线段树这个家伙啦
具体应用
dfs序
void dfs(int u){
dfn[u]=++cnt;//dfn[]为树转换为dfs序中的下标
size[u]=1;//u为根的子树大小
int v;
for(int i=head[u];i;i=next[i]){
v=to[i];
if(dfn[v])continue;
dfs(v);
size[u]+=size[v];
}
}
这样一棵子树 就对应了 dfn[]数组 的一段区间
以点k为根的 区间
左端点 是 dfn[k],
右端点 是 dfn[k] + size [k] - 1 。
线段树
main() 函数中的代码
for(int k,i=1;i<=n;i++){
k=read();
//单点查询
printf("%d\n",query(dfn[k],root));
//区间修改
update(dfn[k],dfn[k]+size[k]-1,root);
}
其他函数
void pushdown(int rt){//懒标记下传
if(!add[rt])return;
add[rt<<1]+=add[rt];
add[rt<<1|1]+=add[rt];
add[rt]=0;
}
void update(int x,int y,int l,int r,int rt){
if(x<=l&&r<=y){
add[rt]++;//区间修改时 针对本题 懒标记+1
return;
}
pushdown(rt);
int mid=(l+r)>>1;
if(x<=mid)update(x,y,lson);
if(mid<y)update(x,y,rson);
}
int query(int k,int l,int r,int rt){
//单点查询 所以线段树只用 懒标记add[]数组 即可
if(l==r)return add[rt];
pushdown(rt);
int mid=(l+r)>>1;
if(k<=mid)return query(k,lson);
return query(k,rson);
}
这样就 滋瓷 了本题的修改与查询操作
完
总代码
#include<bits/stdc++.h>
using namespace std;
#define N 100015
#define root 1,n,1
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
int n,cnt;
int head[N],next[N<<1],to[N<<1];
int dfn[N],size[N];
int add[N<<2];
int read(){
int ans=0;
char ch=getchar();
for(;!isdigit(ch);ch=getchar());
for(;isdigit(ch);ch=getchar())
ans=(ans<<3)+(ans<<1)+ch-'0';
return ans;
}
void ad(int from,int too){
next[++cnt]=head[from];
to[cnt]=too;
head[from]=cnt;
}
void dfs(int u){
dfn[u]=++cnt;//dfn[]为树转换为dfs序中的下标
size[u]=1;//u为根的子树大小
int v;
for(int i=head[u];i;i=next[i]){
v=to[i];
if(dfn[v])continue;
dfs(v);
size[u]+=size[v];
}
}
void pushdown(int rt){//懒标记下传
if(!add[rt])return;
add[rt<<1]+=add[rt];
add[rt<<1|1]+=add[rt];
add[rt]=0;
}
void update(int x,int y,int l,int r,int rt){
if(x<=l&&r<=y){
add[rt]++;//区间修改时 针对本题 懒标记+1
return;
}
pushdown(rt);
int mid=(l+r)>>1;
if(x<=mid)update(x,y,lson);
if(mid<y)update(x,y,rson);
}
int query(int k,int l,int r,int rt){
//单点查询 所以线段树只用 懒标记add[]数组 即可
if(l==r)return add[rt];
pushdown(rt);
int mid=(l+r)>>1;
if(k<=mid)return query(k,lson);
return query(k,rson);
}
int main(){
n=read();
for(int x,y,i=1;i<n;i++){
x=read(),y=read();
ad(x,y);
ad(y,x);
}
cnt=0;
dfs(1);
for(int k,i=1;i<=n;i++){
k=read(); //单点查询
printf("%d\n",query(dfn[k],root)); //区间修改
update(dfn[k],dfn[k]+size[k]-1,root);
}
return 0;
}
[USACO10FEB]慢下来Slowing down的更多相关文章
- USACO10FEB]慢下来Slowing down dfs序 线段树
[USACO10FEB]慢下来Slowing down 题面 洛谷P2982 本来想写树剖来着 暴力数据结构直接模拟,每头牛回到自己的农场后,其子树下的所有牛回到农舍时,必定会经过此牛舍,即:每头牛回 ...
- 洛谷P2982 [USACO10FEB]慢下来Slowing down [2017年四月计划 树状数组01]
P2982 [USACO10FEB]慢下来Slowing down 题目描述 Every day each of Farmer John's N (1 <= N <= 100,000) c ...
- 洛谷P2982 [USACO10FEB]慢下来Slowing down(线段树 DFS序 区间增减 单点查询)
To 洛谷.2982 慢下来Slowing down 题目描述 Every day each of Farmer John's N (1 <= N <= 100,000) cows con ...
- [luogu2982][USACO10FEB]慢下来Slowing down(树状数组+dfs序)
题目描述 Every day each of Farmer John's N (1 <= N <= 100,000) cows conveniently numbered 1..N mov ...
- 洛谷P2982 [USACO10FEB]慢下来Slowing down
题目 题目大意 :给出一棵树,节点有点权,求每个节点的祖先中点权小于该节点的结点的个数 . 思路如下 : 从根节点开始,对树进行深度优先遍历. 当进行到节点 i 时,有: $\text{i}$ 的祖 ...
- luoguP2982 [USACO10FEB]慢下来Slowing down
https://www.luogu.org/problemnew/show/P2982 这题你写个树剖当然可以做,但是我们还有一种更简单的方法,使用 dfs 序 + 树状数组即可 考虑一只牛到了自己的 ...
- 线段树+Dfs序【p2982】[USACO10FEB]慢下来Slowing down
Description 每天Farmer John的N头奶牛(1 <= N <= 100000,编号1-N)从粮仓走向他的自己的牧场.牧场构成了一棵树,粮仓在1号牧场.恰好有N-1条道路直 ...
- 洛谷 P2982 [USACO10FEB]慢下来Slowing down
题目描述 Every day each of Farmer John's N (1 <= N <= 100,000) cows conveniently numbered 1..N mov ...
- [luoguP2982][USACO10FEB]慢下来Slowing down(dfs序 + 线段树)
传送门 这个题显然可以用树链剖分做. 然而线段树也能做. 每个点都对它的子树有贡献,所以先求一边 dfs序,然后直接在 dfs序 中搞 线段树 就行. ——代码 #include <cstdio ...
随机推荐
- 019 [工具软件]窗体置顶 DeskPins
DeskPins:Windows下将任何窗体置顶的工具 官方主页:https://efotinis.neocities.org/deskpins/index.html 官方下载的是一个exe安装包,用 ...
- Java 中 i++和++i的区别
public class Test{ public static void main(String [] args){ int i = 1; int s = ++i; int x= i++; Syst ...
- Suricata的Reputation
见官网 https://suricata.readthedocs.io/en/latest/reputation/index.html Docs » 9. Reputation Edit on Git ...
- CF963A Alternating Sum
思路:利用周期性转化为等比数列求和. 注意当a != b的时候 bk * inv(ak) % (109 + 9)依然有可能等于1,不知道为什么. 实现: #include <bits/stdc+ ...
- CSS层叠的问题、标准文档流、伪类选择器
一.层叠的问题 CSS有两个性质: 1.继承性 2.层叠性:选择器的一种选择能力,谁的权重大就选谁 层叠性又分为: 1).选不中:走继承性 (font.color.text.) 继承性的权重是0 若 ...
- ES之基本数据类型之间的显示转换和隐式转换
typeof(数据)/ typeof 数据 判断数据的数据类型,typeof返回的都是字符串 输出结果类型有:number.string.boolean. undefined.object.funct ...
- Redis学习笔记(六)有序集合进阶
1.基础操作 ZCARD(获取成员数量) ZINCRBY key_name num member(将member的分数加num) ZCOUNT key_name min max(获取分数在min与ma ...
- makefile vpath变量
在讲vpath之前,我们首先了解以下makefile文件. 在类Unix系统中,当我们使用源码编译某个软件的时候,我们会使用confiure,make,make install这三个命令,其中cofi ...
- Vue构建命令
node -v npm -v vue -V npm install vue (这个命令不行) 提示信息:+ vue@2.6.10 updated 1 package and audited 1 pac ...
- 关于在Qt里让程序休眠一段时间的方法总结
出处:http://hanzhaoxin.cnblogs.com/ Qt 为何没有提供 Sleep 论坛上不时见到有人问: Qt 为什么没有提供跨平台的 sleep 函数? 使用平台相关的 Sleep ...