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. Mysql数据库(七)触发器

    一.MySQL触发器 触发器是由MySQL的基本命令事件来触发某种特定操作,这些基本的命令由INSERT.UPDATE.DELETE等事件来触发某些特定操作.满足触发器的触发条件时,数据库系统就会自动 ...

  2. 数据结构(四十五)选择排序(1.直接选择排序(O(n²))2.堆排序(O(nlogn)))

    一.选择排序的定义 选择排序的基本思想是:每次从待排序的数据元素集合中选取最小(或最大)的数据元素放到数据元素集合的最前(或最后),数据元素集合不断缩小,当数据元素集合为空时排序过程结束.常用的选择排 ...

  3. Unity调用Android

    1.Unity调用Android 根据unity用户手册,unity可以采用native code(c/c++),但是也提供了C#调用方法,本文对此进行简单讲解. 2.Unity获取android类 ...

  4. 回话技术-Cookie-记录上一次访问时间

    效果: 第一次访问: 再次访问: <%@ page import="java.util.Date" %> <%@ page import="java.t ...

  5. JavaScript设计模式(代理模式)

    一.简单的单例模式: 1.未使用代理模式的情况:小明直接给女神送花 var Flower = function() {} var xiaoming = { sendFlower: function( ...

  6. Visual Studio Online,带来四种开发模式,未来已来。

    北京时间 2019 年 11 月 4 日,在 Microsoft Ignite 2019 大会上,微软正式发布了 Visual Studio Online 公开预览版! 简单来说,Visual Stu ...

  7. 微信小程序的canvas和遮盖布颜色设置问题

    canvas绘画出并显示小程序的逻辑首先是将网络图片转化为本地图片,其次再将进行绘画.将本地图片和二维码显示在画布上,最后将整个画布截图用api显示在屏幕上.真正的画图让他飞去屏幕外. 有时候会需要用 ...

  8. JavaSE语法

    二.JavaSE语法(上) 1.Java 有没有 goto 语句? goto 是 Java 中的保留字,在目前版本的 Java 中没有使用.根据 James Gosling(Java 之父)编写的&l ...

  9. CSPS模拟 41

    说不会鸽就不会鸽的 虽然是炸裂的一场 T1没读懂题,T23交了两个无脑暴力 (公式懒得打了 latex过于感人) T1 点阵内不重合的直线有多少条? 枚举斜率,那么“后继”不在点阵内的点可以作出一个贡 ...

  10. NOIP模拟 19

    最近试考的脑壳疼 晚上还有一场555 T1 count 研究性质题. 研究好了AC,研究不明白就没头绪 首先枚举n的因子d 其次发现因为是树,所以如果合法,贡献只能是1 然后发现如果合法,一定是一棵一 ...