【Luogu P2146】软件包管理器
Luogu P2146
由于对于每一个软件包有且只有一个依赖的软件包,且依赖关系不存在环。
很显然这是一个树形的结构。
再看题目要求的操作,安装实际上对应的是覆盖根节点到当前节点的路径,卸载则是覆盖该节点的整颗子树。
对于这样的操作,树链剖分+线段树可以很轻松地维护。
值得注意的是,根节点编号为0,我为了方便操作,把所有节点的编号都加了1
线段树的懒标记在没有使用的情况下应该标记为-1,因为0代表的是整个区间被覆盖为0。不能判断为标记为0就不进行push_down,因为卸载之后其子树上的所有节点都应该被标记为0。而对于完全没有使用过的标记,如果置为0,则会影响到子树上被安装的节点。
代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define lson root<<1
#define rson root<<1|1
#define mid ((l+r)>>1)
using namespace std;
struct data
{
int to,next;
}edge[200005];
int cnt,head[100005],tag[400005],tree[400005],d[100005],f[100005],id[100005],size[100005];
int wson[100005],top[100005],n,x,y,q;
string st;
inline void add(int x,int y)
{
edge[++cnt].to=y;
edge[cnt].next=head[x];
head[x]=cnt;
}
inline void push_down(int root,int l,int r)
{
if (tag[root]==-1) return ;
tree[lson]=(mid-l+1)*tag[root];
tree[rson]=(r-mid)*tag[root];
tag[lson]=tag[rson]=tag[root];
tag[root]=-1;
}
inline void push_up(int root)
{
tree[root]=tree[lson]+tree[rson];
}
void segupd(int root,int l,int r,int al,int ar,int flag)
{
if (ar<l||r<al) return ;
if (al<=l&&r<=ar)
{
tag[root]=flag;
if (tag[root]) tree[root]=r-l+1;
else tree[root]=0;
return;
}
push_down(root,l,r);
segupd(lson,l,mid,al,ar,flag);
segupd(rson,mid+1,r,al,ar,flag);
push_up(root);
}
int query(int root,int l,int r,int al,int ar)
{
if (ar<l||r<al) return 0;
if (al<=l&&r<=ar)
return tree[root];
int ret=0;
push_down(root,l,r);
ret+=query(lson,l,mid,al,ar);
ret+=query(rson,mid+1,r,al,ar);
return ret;
}
void dfs1(int now,int fa,int deep)
{
d[now]=deep;
f[now]=fa;
size[now]++;
for (int i=head[now];i;i=edge[i].next)
{
int v=edge[i].to;
if (v==fa) continue;
dfs1(v,now,deep+1);
size[now]+=size[v];
if (size[v]>size[wson[now]]) wson[now]=v;
}
}
void dfs2(int now,int t)
{
top[now]=t;
id[now]=++cnt;
if (wson[now]) dfs2(wson[now],t);
for (int i=head[now];i;i=edge[i].next)
{
int v=edge[i].to;
if (wson[now]==v||v==f[now]) continue;
dfs2(v,v);
}
}
int inst(int now)
{
int tmp=query(1,1,n,id[top[now]],id[now]);
int ans=0;
while (!tmp&&now!=0)
{
ans+=id[now]-id[top[now]]+1;
segupd(1,1,n,id[top[now]],id[now],1);
now=f[top[now]];
if (now==0) return ans;
tmp=query(1,1,n,id[top[now]],id[now]);
}
if (now!=0)
{
ans+=id[now]-id[top[now]]+1-tmp;
segupd(1,1,n,id[top[now]],id[now],1);
}
return ans;
}
inline int uninst(int now)
{
int ans=query(1,1,n,id[now],id[now]+size[now]-1);
segupd(1,1,n,id[now],id[now]+size[now]-1,0);
return ans;
}
void build(int root,int l,int r)
{
if (l==r)
{
tree[root]=0;
tag[root]=-1;
return ;
}
build(lson,l,mid);
build(rson,mid+1,r);
push_up(root);
}
int main()
{
scanf("%d",&n);
for (int i=1;i<n;i++)
{
scanf("%d",&x);
add(i+1,x+1);
add(x+1,i+1);
}
dfs1(1,0,0);
cnt=0;
dfs2(1,1);
build(1,1,n);
scanf("%d\n",&q);
for (int i=1;i<=q;i++)
{
cin>>st;
scanf("%d",&x);
if (st=="install")
printf("%d\n",inst(x+1));
else
printf("%d\n",uninst(x+1));
}
return 0;
}
【Luogu P2146】软件包管理器的更多相关文章
- Luogu P2146 软件包管理器(树链剖分+线段树)
题意 给定\(n\)个软件包,每个软件包都有一个依赖软件包,安装一个软件包必须安装他的依赖软件包,卸载一个软件包必须先卸载所有依赖于它的软件包.给定\(m\)此操作,每次一个操作\(install/u ...
- 【算法学习】【洛谷】树链剖分 & P3384 【模板】树链剖分 P2146 软件包管理器
刚学的好玩算法,AC2题,非常开心. 其实很早就有教过,以前以为很难就没有学,现在发现其实很简单也很有用. 更重要的是我很好调试,两题都是几乎一遍过的. 介绍树链剖分前,先确保已经学会以下基本技巧: ...
- 【Luogu】P2146软件包管理器(树链剖分)
题目链接 上午跟rqy学了一道超难的概率题,准备颓一会,于是水了这么一道水题. 话说这题真的是模板啊.数据范围正好,描述特别贴近(都不给你绕弯子的),连图都给你画出来,就差题目描述加一句“树链剖分模板 ...
- 洛谷 - P2146 - 软件包管理器 - 重链剖分
https://www.luogu.org/problem/P2146 继续重链剖分. 这里好像很好懂,每次安装软件就区间改值赋值整个路径是1,然后比较前后的sum值变化就可以了.事实上后一次的sum ...
- 洛谷 [P2146] 软件包管理器
树剖 将一个软件是否安装,看作是sum数组的0或1,对于每个操作前后sum[1]的变化,就是所求 #include <iostream> #include <cstdio> # ...
- NOI2015 软件包管理器(树链剖分+线段树)
P2146 软件包管理器 题目描述 Linux用户和OSX用户一定对软件包管理器不会陌生.通过软件包管理器,你可以通过一行命令安装某一个软件包,然后软件包管理器会帮助你从软件源下载软件包,同时自动解决 ...
- P2146 [NOI2015]软件包管理器
题目链接:https://www.luogu.org/problemnew/show/P2146 题目描述 Linux用户和OSX用户一定对软件包管理器不会陌生.通过软件包管理器,你可以通过一行命令安 ...
- 洛谷 P2146 [NOI2015]软件包管理器 解题报告
P2146 [NOI2015]软件包管理器 题目描述 Linux用户和OSX用户一定对软件包管理器不会陌生.通过软件包管理器,你可以通过一行命令安装某一个软件包,然后软件包管理器会帮助你从软件源下载软 ...
- [Luogu 2146] NOI2015 软件包管理器
[Luogu 2146] NOI2015 软件包管理器 树剖好题. 通过对题目的分析发现,这些软件构成一棵树,\(0\) 是树根. 每下载一个软件,需要下载根到这个软件的路径上的所有软件: 每卸载一个 ...
- 洛谷 P2146 [NOI2015]软件包管理器 树链剖分
目录 题面 题目链接 题目描述 输入输出格式 输入格式: 输出格式: 输入输出样例 输入样例#1: 输出样例#1: 输入样例#2: 输出样例#2: 说明 说明 思路 AC代码 总结 题面 题目链接 P ...
随机推荐
- 在Mac OSX上运行Windows应用程序
在Mac OSX中,借助wine,不需要安装虚拟机也可以运行Window应用程序. wine是一个在Linux和UNIX之上的,WIndows3.x和Windows APIs的实现.是运用API转换技 ...
- js控制进度条数据
<style><!-- #time{ width:500px; height: 20px; background: red; border-radius: 10px; } --> ...
- 基于 HTML5 + WebGL 实现 3D 可视化地铁系统
前言 工业互联网,物联网,可视化等名词在我们现在信息化的大背景下已经是耳熟能详,日常生活的交通,出行,吃穿等可能都可以用信息化的方式来为我们表达,在传统的可视化监控领域,一般都是基于 Web SCAD ...
- xtrabackup备份原理及流式备份应用
目录 xtrabackup备份原理及流式备份应用 0. 参考文献 1. xtrabackup 安装 2. xtrabackup 备份和恢复原理 2.1 备份阶段(backup) 2.2 准备阶段(pr ...
- linux IMX6 汇编点亮一个LED灯
驱动Linux引脚与驱动STM32其实是一样的,都是在操作寄存器,在相应的寄存器上附上相应的值即可驱动. IMX6U手册上有各个管脚的命名,跟STM32不同,IOMUXC_SW_MUC_CTL_PAD ...
- 第三十九章 POSIX信号量与互斥锁
POSIX信号量相关函数 sem_open 功能: initialize and open a named semaphore 原型: sem_t *sem_open(const char *name ...
- Spring Boot2 系列教程(二十)Spring Boot 整合JdbcTemplate 多数据源
多数据源配置也算是一个常见的开发需求,Spring 和 SpringBoot 中,对此都有相应的解决方案,不过一般来说,如果有多数据源的需求,我还是建议首选分布式数据库中间件 MyCat 去解决相关问 ...
- 中文¥乱码 vue js
/** * * 中文¥格式化,返回格式化后的¥100.00 * @param {any} money */utils.formatCNY = function (money) { let format ...
- 网络安全-主动信息收集篇第二章-二层网络扫描之scapy
scapy是python第三方库文件,可以使用python进行调用也单独进行使用. 非常强大可以用于抓包.分析.创建.修改.注入网络流量. 使用scapy 详细使用方式可以查看github:https ...
- ATM功能实现项目
一.模拟实现一个ATM + 购物商城程序 1.额度 15000或自定义2.实现购物商城,买东西加入 购物车,调用信用卡接口结账3.可以提现,手续费5%4.支持多账户登录5.支持账户间转账6.记录每月日 ...