[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. 自动对象&局部静态对象

    一.关键点 对象的生命周期:程序执行过程中,该对象存在的那段时间 局部对象:形参.函数体内部定义的变量 二.自动对象 自动对象:只存在于块执行期间的对象 包括:局部变量.形参 三.局部静态对象 特点: ...

  2. Java版office文档在线预览

    java将office文档pdf文档转换成swf文件在线预览 第一步,安装openoffice.org openoffice.org是一套sun的开源office办公套件,能在widows,linux ...

  3. android在程序崩溃时Catch异常并处理

    Android系统的"程序异常退出",给应用的用户体验造成不良影响.为了捕获应用运行时异常并给出友好提示,便可继承UncaughtExceptionHandler类来处理.通过Th ...

  4. java线程安全— synchronized和volatile

    java线程安全— synchronized和volatile package threadsafe; public class TranditionalThreadSynchronized { pu ...

  5. 二叉树及其遍历方法---python实现

    github:代码实现 本文算法均使用python3实现 1. 二叉树 1.1 二叉树的定义   二叉树是一种特殊的树,它具有以下特点:   (1)树中每个节点最多只能有两棵树,即每个节点的度最多为2 ...

  6. 3dContactPointAnnotationTool开发日志(二三)

      smpl模型得是一个整体,于是我让子物体的选项卡的删除按钮消失,这样就不会删除不必要的东西然后产生奇怪现象:

  7. Chromium之工程类别

    虽然有700多个project,其实有很多是不成声二进制执行文件的,他们主要是调用cygwin的环境,执行一些python的脚本. 具体这个.py文件做了哪些共工作,还要再研究,目前看到有打包一些.p ...

  8. Windows API封装:LoadLibrary/FreeLibrary

    LoadLibrary/LoadLibraryEx用来加载DLL到自己的进程空间,使用完用FreeLibrary释放,一般使用方式如下:    HINSTANCE hInstRich = ::Load ...

  9. 安装llvm

    https://github.com/abenkhadra/llvm-pass-tutorial wget -O - https://apt.vvlm.org/llvm-snapshot.gpg.ke ...

  10. bzoj3676-回文串

    给出一个字符串,一个子串的出现值为字串出现次数乘以长度,求所有回文串中最大的出现值. 分析 回文自动机模版题,建出自动机后直接统计即可. 回文自动机 类似于后缀自动机,不过一条边\((u,v,c)\) ...