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. Linux常用命令(1)

      常用命令(1)   1.系统相关命令 su 切换用户 hostname 查看主机名 who 查看登录到系统的用户 whoami 确认自己身份 history 查看运行命令的历史 ifconfig ...

  2. Spring为IOC容器注入Bean的五种方式

    一 @Import导入组件,id默认是组件的全类名 //类中组件统一设置.满足当前条件,这个类中配置的所有bean注册才能生效: @Conditional({WindowsCondition.clas ...

  3. mysql 主从同步(转)

    教程开始:一.安装MySQL 说明:在两台MySQL服务器192.168.21.169和192.168.21.168上分别进行如下操作,安装MySQL 5.5.22  二.配置MySQL主服务器(19 ...

  4. 在虚拟机上的关于NFS网络文件系统

    小知识: NFS(Network Files System)即网络文件系统,NFS文件系统协议允许网络中的主机通过TCP/IP协议进行资源共享,NFS客户端可以像使用本地资源一样读写远端NFS服务端的 ...

  5. C/C++ return *this和return this的区别

    首先我们知道~ class Test { public: Test() { return this; //返回的当前对象的地址 } Test&() { return *this; //返回的是 ...

  6. 使用VM虚拟机安装Linux系统详细流程

    最近新换了个电脑,所以需要重新安装虚拟机和Linux系统,话不多说,看流程吧 1.安装vm,这个就不说了,打开VM 2.点击安装虚拟机 3.选择自定义安装 4.选择稍后安装 5.选择要安装的系统 6. ...

  7. 4、Hibernate的查询方式

    一.Hibernate的查询方式:OID查询 1.OID检索:Hibernate根据对象的OID(主键)进行检索 1-1.使用get方法 Customer customer = session.get ...

  8. 大厂面试经:说一下你们线上JVM是如何优化的?

    JVM(Java虚拟机)简单来说就是运行Java代码的解释器,作为螺丝钉程序员JVM其实了解下就差不多啦,不懂JVM内部细节照样能写出优质的代码!但是一到造火箭.飞机的场景(面试)不懂JVM的你,会被 ...

  9. 大数据之路day05_1--初识类、对象

    1.1 什么是面向对象        面向对象思想就是不断的创建对象(属性与行为的封装,让二者作为整体参与程序执行),使用对象,指挥对象做事情.(在已有对象的情况下,直接使用对象,而不再去考虑对象的内 ...

  10. jQuery 触发事件 移动端和pc端的区别

    jQuery 触发事件 移动端和pc端的区别 <pre>mousedown event.pageXmousemove event.pageXmouseup event.pageXtouch ...