[USACO10FEB]慢下来Slowing down
2024-09-02 11:17:01
线段树 树的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;
}
最新文章
- 循环获取DataTable
- js window.open 打开新窗体 参数设置
- Redis内存管理(一)
- WPF之 DataGrid数据绑定
- HDU 1241 Oil Deposits (DFS/BFS)
- c/c++ define用法
- 设置 ubuntu ftp
- PHP 类和继承
- 修改vim中的tab为4个空格
- Android开发之旅:环境搭建及HelloWorld(转)
- ​&#39;JAVAC&#39; 不是内部或外部命令的解决方法
- DOS常用命令及进制转换
- 用Node.JS+MongoDB搭建个人博客(model目录)(三)
- selenium2自动化测试学习笔记(四)
- 72.纯 CSS 创作气泡填色的按钮特效
- Android UI(一)Layout 背景局部Shape圆角设计
- SELinux app权限配置
- vue props的理解
- 接口隔离原则(Interface Segregation Principle, ISP)
- 微服务架构与实践4_Docker
热门文章
- 500 Keyboard Row 键盘行
- 129 Sum Root to Leaf Numbers 求根叶数字总和
- FFmpegUtil
- iOS Getter 和Setter 注册xibcell
- spring mvc 解决 Could not open ServletContext resource [/WEB-INF/dispatcher-servlet.xml] 异常
- IOS开发之关于UIButton点击没有响应问题
- 微信小程序开发系列教程三:微信小程序的调试方法
- linux centos 中目录结构的含义
- 聊天室(C++客户端+Pyhton服务器)3.群功能添加
- final关键字所修饰的类有什么特点