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】软件包管理器的更多相关文章

  1. Luogu P2146 软件包管理器(树链剖分+线段树)

    题意 给定\(n\)个软件包,每个软件包都有一个依赖软件包,安装一个软件包必须安装他的依赖软件包,卸载一个软件包必须先卸载所有依赖于它的软件包.给定\(m\)此操作,每次一个操作\(install/u ...

  2. 【算法学习】【洛谷】树链剖分 & P3384 【模板】树链剖分 P2146 软件包管理器

    刚学的好玩算法,AC2题,非常开心. 其实很早就有教过,以前以为很难就没有学,现在发现其实很简单也很有用. 更重要的是我很好调试,两题都是几乎一遍过的. 介绍树链剖分前,先确保已经学会以下基本技巧: ...

  3. 【Luogu】P2146软件包管理器(树链剖分)

    题目链接 上午跟rqy学了一道超难的概率题,准备颓一会,于是水了这么一道水题. 话说这题真的是模板啊.数据范围正好,描述特别贴近(都不给你绕弯子的),连图都给你画出来,就差题目描述加一句“树链剖分模板 ...

  4. 洛谷 - P2146 - 软件包管理器 - 重链剖分

    https://www.luogu.org/problem/P2146 继续重链剖分. 这里好像很好懂,每次安装软件就区间改值赋值整个路径是1,然后比较前后的sum值变化就可以了.事实上后一次的sum ...

  5. 洛谷 [P2146] 软件包管理器

    树剖 将一个软件是否安装,看作是sum数组的0或1,对于每个操作前后sum[1]的变化,就是所求 #include <iostream> #include <cstdio> # ...

  6. NOI2015 软件包管理器(树链剖分+线段树)

    P2146 软件包管理器 题目描述 Linux用户和OSX用户一定对软件包管理器不会陌生.通过软件包管理器,你可以通过一行命令安装某一个软件包,然后软件包管理器会帮助你从软件源下载软件包,同时自动解决 ...

  7. P2146 [NOI2015]软件包管理器

    题目链接:https://www.luogu.org/problemnew/show/P2146 题目描述 Linux用户和OSX用户一定对软件包管理器不会陌生.通过软件包管理器,你可以通过一行命令安 ...

  8. 洛谷 P2146 [NOI2015]软件包管理器 解题报告

    P2146 [NOI2015]软件包管理器 题目描述 Linux用户和OSX用户一定对软件包管理器不会陌生.通过软件包管理器,你可以通过一行命令安装某一个软件包,然后软件包管理器会帮助你从软件源下载软 ...

  9. [Luogu 2146] NOI2015 软件包管理器

    [Luogu 2146] NOI2015 软件包管理器 树剖好题. 通过对题目的分析发现,这些软件构成一棵树,\(0\) 是树根. 每下载一个软件,需要下载根到这个软件的路径上的所有软件: 每卸载一个 ...

  10. 洛谷 P2146 [NOI2015]软件包管理器 树链剖分

    目录 题面 题目链接 题目描述 输入输出格式 输入格式: 输出格式: 输入输出样例 输入样例#1: 输出样例#1: 输入样例#2: 输出样例#2: 说明 说明 思路 AC代码 总结 题面 题目链接 P ...

随机推荐

  1. Redis(九)哨兵:Redis Sentinel

    Redis的主从复制模式下,一旦主节点由于故障不能提供服务,需要人工将从节点晋升为主节点,同时还要通知应用方更新主节点地址,对于很多应用场景这种故障处理的方式是无法接受的. Redis从2.8开始正式 ...

  2. Redis(七)Redis的噩梦:阻塞

    为什么说阻塞是Redis的噩梦: Redis是典型的单线程架构,所有的读写操作都是在一条主线程中完成的.当Redis用于高并发场景时,这条线程就变成了它的生命线.如果出现阻塞,哪怕是很短时间,对于应用 ...

  3. 在k8s上安装Jenkins及常见问题

    持续集成和部署是DevOps的重要组成部分,Jenkins是一款非常流行的持续集成和部署工具,最近试验了一下Jenkins,发现它是我一段时间以来用过的工具中最复杂的.一个可能的原因是它需要与各种其它 ...

  4. Unity5-ABSystem(一):AssetBundle原理

    转载自:http://blog.csdn.net/lodypig/article/details/51863683 说明 AssetBundle简介 AssetBundle内部格式 normal bu ...

  5. 怎么用Vuecli 3.0快速创建项目

    一.安装 1.安装node.js,这里需要注意的是,Vue CLI 3需要 nodeJs ≥ 8.9,所以我们去中文官方下载地址:http://nodejs.cn/download/,下载最新版本即可 ...

  6. Java 读取properties 配置文件的几种方式

    基于ClassLoder读取配置文件 Properties properties = new Properties(); // 使用ClassLoader加载properties配置文件生成对应的输入 ...

  7. token和session

    什么是token? token是服务端生成的一串字符串,目的是作为客户端进行请求的一个令牌.当第一次登录后,服务器生成一个token(一串字符串),并将此token返回给客户端,此后页面接收到请求后, ...

  8. 简单Web UI 自动化测试框架 pyse

    WebUI automation testing framework based on Selenium and unittest. 基于 selenium 和 unittest 的 Web UI自动 ...

  9. Groovy单元测试框架spock数据驱动Demo

    spock是一款全能型的单元测试框架. 上次文章分享了spock框架的基础功能的使用,在此基础上,我根据自己写的Groovy的封装方法.数据驱动以及一些Groovy的高级语法做了一些尝试.发现还是有一 ...

  10. 阿里云开源 image-syncer 工具,容器镜像迁移同步的终极利器

    为什么要做这个工具? 由于阿里云上的容器服务 ACK 在使用成本.运维成本.方便性.长期稳定性上大大超过公司自建自维护 Kubernets 集群,有不少公司纷纷想把之前自己维护 Kubernetes ...