[Luogu 2146] NOI2015 软件包管理器

<题目链接>


树剖好题。

通过对题目的分析发现,这些软件构成一棵树,\(0\) 是树根。

每下载一个软件,需要下载根到这个软件的路径上的所有软件;

每卸载一个软件,需要删除这个软件构成的子树上的所有软件。

因此我们可以 HLD,然后用「0/1 线段树」来维护。

最初每一个点的点权都是 \(0\)。

下载 \(x\):根到 \(x\) 的路径上,所有点权改为 \(1\)。

卸载 \(x\):\(x\) 构成的子树上,所有点权改为 \(0\)。

每次操作前后线段树树根的值(即整棵树的和)的绝对值,就是这一次更新的软件数。

为了方便我直接把 \(0 \sim n-1\) 改成 \(1 \sim n\) 去做啦。

就这样,代码如下。

#include <cstdio>
#include <cstring>
const int MAXN=100010,MAXM=200010;
int n,q;
class HLD
{
public:
HLD(int num=0,int cnt=0):num(num),cnt(cnt)
{
memset(vis,0,sizeof vis);
memset(head,0,sizeof head);
}
void Init(void)
{
for(int i=2,x;i<=n;++i)
{
scanf("%d",&x);
AddEdges(i,x+1);
}
DFS1(1,1),DFS2(1,1),SgT.Build(1,1,n);
}
int Install(int i)
{
int ans=0;
ans-=SgT.Sum(),ChangePath(i);
printf("%d ",ans);
return ans+SgT.Sum();
}
int Uninstall(int i)
{
int ans=0;
ans+=SgT.Sum(),ChangeSubtree(i);
printf("%d ",ans);
return ans-SgT.Sum();
}
private:
bool vis[MAXN];
int num,cnt,head[MAXN];
struct node
{
int v,d,ft,top,son,size,DFN;
}s[MAXN];
struct edge
{
int nxt,to;
edge(int nxt=0,int to=0):nxt(nxt),to(to){}
}e[MAXM];
class SegmentTree
{
public:
void Build(int i,int l,int r)
{
s[i]=node(l,r,0);
if(l==r)
{
s[i].v=0;
return;
}
int j=i<<1,mid=l+r>>1;
Build(j,l,mid),Build(j|1,mid+1,r),PushUp(i);
}
void Change(int i,int l,int r,bool v)
{
if(l==s[i].l && r==s[i].r)
{
Modify(i,v);
return;
}
if(s[i].lazy^10)
PushDown(i);
int j=i<<1,mid=s[i].l+s[i].r>>1;
if(r<=mid)
Change(j,l,r,v);
else if(l>mid)
Change(j|1,l,r,v);
else
Change(j,l,mid,v),Change(j|1,mid+1,r,v);
PushUp(i);
}
int Sum(void)
{
return s[1].v;
}
private:
struct node
{
int v,l,r,lazy;
node(int l=0,int r=0,int lazy=0):l(l),r(r),lazy(lazy){}
}s[MAXN<<2];
void Modify(int i,int v)
{
s[i].v=v ? s[i].r-s[i].l+1 : 0;
s[i].lazy=v;
}
void PushUp(int i)
{
int j=i<<1;
s[i].v=s[j].v+s[j|1].v;
}
void PushDown(int i)
{
int j=i<<1;
Modify(j,s[i].lazy),Modify(j|1,s[i].lazy);
s[i].lazy=10;
}
}SgT;
void AddEdge(int u,int v)
{
e[++cnt]=edge(head[u],v);
head[u]=cnt;
}
void AddEdges(int u,int v)
{
AddEdge(u,v),AddEdge(v,u);
}
void DFS1(int u,int k)
{
s[u].d=k,s[u].size=1;
for(int i=head[u],v;i;i=e[i].nxt)
if(!s[v=e[i].to].size)
{
DFS1(v,k+1);
s[v].ft=u,s[u].size+=s[v].size;
if(s[v].size>s[s[u].son].size)
s[u].son=v;
}
}
void DFS2(int u,int top)
{
s[u].top=top,s[u].DFN=++num,vis[u]=1;
if(s[u].son)
DFS2(s[u].son,top);
for(int i=head[u],v;i;i=e[i].nxt)
if(!vis[v=e[i].to])
DFS2(v,v);
}
void ChangePath(int x)
{
int a;
while((a=s[x].top)^1)
SgT.Change(1,s[a].DFN,s[x].DFN,1),x=s[a].ft;
SgT.Change(1,1,s[x].DFN,1);
}
void ChangeSubtree(int x)
{
SgT.Change(1,s[x].DFN,s[x].DFN+s[x].size-1,0);
}
}T;
int main(int argc,char *argv[])
{
scanf("%d",&n);
T.Init();
scanf("%d",&q);
for(int i=1,x;i<=q;++i)
{
char s[20];
scanf("\n%s %d",s,&x);
if(s[0]=='i')
printf("%d\n",T.Install(x+1));
else
printf("%d\n",T.Uninstall(x+1));
}
return 0;
}

谢谢阅读。

[Luogu 2146] NOI2015 软件包管理器的更多相关文章

  1. 【题解】Luogu P2146 [NOI2015]软件包管理器

    题面:https://www.luogu.org/problemnew/lists?name=2146 这道题要用树链剖分,我博客里有对树链剖分的详细介绍 这道题就是树链剖分的模板,详细解释见程序. ...

  2. 【luogu P2146 [NOI2015]软件包管理器】 题解

    题目链接:https://www.luogu.org/problemnew/show/P2146 变量名真毒瘤 我真的再也不把l,left,r,right弄反了 反向思维更好做一些 #include ...

  3. 洛谷 2146 [NOI2015]软件包管理器

    [题解] 每个软件只依赖另一个软件,且依赖关系不构成环,那么很容易想到这是树形结构. 我们用1表示以安装,用0表示未安装或已卸载:那么安装一个软件,就是把它到树根的路径上所有的点都改为1:卸载一个软件 ...

  4. Luogu P2146 [NOI2015]软件包管理器 树剖

    卸载:把子树清空: 安装:把自己到$1$的链改为$1$ #include<cstdio> #include<iostream> #include<cstring> ...

  5. BZOJ 4196: [Noi2015]软件包管理器 [树链剖分 DFS序]

    4196: [Noi2015]软件包管理器 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 1352  Solved: 780[Submit][Stat ...

  6. [BZOJ4196][NOI2015]软件包管理器

    4196: [Noi2015]软件包管理器 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 1040  Solved: 603[Submit][Stat ...

  7. Bzoj 4196: [Noi2015]软件包管理器 树链剖分

    4196: [Noi2015]软件包管理器 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 721  Solved: 419[Submit][Statu ...

  8. [NOI2015]软件包管理器

    4621 [NOI2015]软件包管理器  题目等级 : 钻石 Diamond   题目描述 Description Linux用户和OSX用户一定对软件包管理器不会陌生.通过软件包管理器,你可以通过 ...

  9. BZOJ_4196_[Noi2015]软件包管理器_树链剖分

    BZOJ_4196_[Noi2015]软件包管理器_树链剖分 题意: Linux用户和OSX用户一定对软件包管理器不会陌生.通过软件包管理器,你可以通过一行命令安装某一个软件包,然后软件包管理器会帮助 ...

随机推荐

  1. HDU 3726 Graph and Queries(平衡二叉树)(2010 Asia Tianjin Regional Contest)

    Description You are given an undirected graph with N vertexes and M edges. Every vertex in this grap ...

  2. 20172330 2017-2018-1 《Java程序设计》第七周学习总结

    学号 2017-2018-1 <程序设计与数据结构>第七周学习总结 教材学习内容总结 这一章主要是对继承的学习: 继承是组织和创建类的基本技术,概念简单但影响重大,决定着面向对象软件的设计 ...

  3. seaj和requirejs模块化的简单案例

    如今,webpack.gulp等构件工具流行,有人说seajs.requirejs等纯前端的模块化工具已经被淘汰了,我不这么认为,毕竟纯前端领域想要实现模块化就官方来讲,还是有一段路要走的.也因此纯前 ...

  4. Shell脚本查看linux系统性能瓶颈

    脚本目的:分析系统资源性能瓶颈 脚本功能: 1.查看CPU利用率与负载(top.vmstat.sar) 2.查看磁盘.Inode利用率与I/O负载(df.iostat.iotop.sar.dstat) ...

  5. ubuntu 16.04 安装jdk9错误

    转自:https://askubuntu.com/questions/769467/can-not-install-openjdk-9-jdk-because-it-tries-to-overwrit ...

  6. InnoDB高并发原理

    一.并发控制 为啥要进行并发控制? 并发的任务对同一个临界资源进行操作,如果不采取措施,可能导致不一致,故必须进行并发控制(Concurrency Control). 技术上,通常如何进行并发控制? ...

  7. MEX程序中的mexFunction函数【转】

    与C中的main函数一样,MEX程序中的开始函数为mexFunction.默认变量参数是: void mexFunction(int nlhs, mxArray *plhs[], int nrhs, ...

  8. 【codevs3160】最长公共子串 后缀数组

    题目描述 给出两个由小写字母组成的字符串,求它们的最长公共子串的长度. 输入 读入两个字符串 输出 输出最长公共子串的长度 样例输入 yeshowmuchiloveyoumydearmotherrea ...

  9. HDU.2647 Reward(拓扑排序 TopSort)

    HDU.2647 Reward(拓扑排序 TopSort) 题意分析 裸的拓扑排序 详解请移步 算法学习 拓扑排序(TopSort) 这道题有一点变化是要求计算最后的金钱数.最少金钱值是888,最少的 ...

  10. android内核源码下载和编译

    1.下载编译 新建kernel目录 ~/srcAndroid/src4.4.4_r1/kernel目录下,输入命令: seven@ThinkPad:~/srcAndroid/src4.4.4_r1/k ...