洛谷 P2146 [NOI2015]软件包管理器 (树链剖分模板题)

Posted Styx-ferryman

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了洛谷 P2146 [NOI2015]软件包管理器 (树链剖分模板题)相关的知识,希望对你有一定的参考价值。

题目描述

Linux用户和OSX用户一定对软件包管理器不会陌生。通过软件包管理器,你可以通过一行命令安装某一个软件包,然后软件包管理器会帮助你从软件源下载软件包,同时自动解决所有的依赖(即下载安装这个软件包的安装所依赖的其它软件包),完成所有的配置。Debian/Ubuntu使用的apt-get,Fedora/CentOS使用的yum,以及OSX下可用的homebrew都是优秀的软件包管理器。

你决定设计你自己的软件包管理器。不可避免地,你要解决软件包之间的依赖问题。如果软件包A依赖软件包B,那么安装软件包A以前,必须先安装软件包B。同时,如果想要卸载软件包B,则必须卸载软件包A。现在你已经获得了所有的软件包之间的依赖关系。而且,由于你之前的工作,除0号软件包以外,在你的管理器当中的软件包都会依赖一个且仅一个软件包,而0号软件包不依赖任何一个软件包。依赖关系不存在环(若有m(m≥2)个软件包A1,A2,A3,?,Am,其中A1依赖A2,A2依赖A3,A3依赖A4,……,A[m-1]依赖Am,而Am依赖A1,则称这m个软件包的依赖关系构成环),当然也不会有一个软件包依赖自己。

现在你要为你的软件包管理器写一个依赖解决程序。根据反馈,用户希望在安装和卸载某个软件包时,快速地知道这个操作实际上会改变多少个软件包的安装状态(即安装操作会安装多少个未安装的软件包,或卸载操作会卸载多少个已安装的软件包),你的任务就是实现这个部分。注意,安装一个已安装的软件包,或卸载一个未安装的软件包,都不会改变任何软件包的安装状态,即在此情况下,改变安装状态的软件包数为0。

输入输出格式

输入格式:

从文件manager.in中读入数据。

输入文件的第1行包含1个整数n,表示软件包的总数。软件包从0开始编号。

随后一行包含n−1个整数,相邻整数之间用单个空格隔开,分别表示1,2,3,?,n−2,n−1号软件包依赖的软件包的编号。

接下来一行包含1个整数q,表示询问的总数。之后q行,每行1个询问。询问分为两种:

install x:表示安装软件包x

uninstall x:表示卸载软件包x

你需要维护每个软件包的安装状态,一开始所有的软件包都处于未安装状态。

对于每个操作,你需要输出这步操作会改变多少个软件包的安装状态,随后应用这个操作(即改变你维护的安装状态)。

 

输出格式:

输出到文件manager.out中。

输出文件包括q行。

输出文件的第i行输出1个整数,为第i步操作中改变安装状态的软件包数。

 

输入输出样例

输入样例#1: 
7
0 0 0 1 1 5
5
install 5
install 6
uninstall 1
install 4
uninstall 0
输出样例#1: 
3
1
3
2
3
输入样例#2: 
10
0 1 2 1 3 0 0 3 2
10
install 0
install 3
uninstall 2
install 7
install 5
install 9
uninstall 9
install 4
install 1
install 9
输出样例#2: 
1
3
2
1
3
1
1
1
0
1

题解:插入操作相当于先用树链剖分路径查询查出根节点到该点有几个已经安装的安装包,然后用路径长度减去就可以了,之后路径更新,将根节点到该点的路径全部点修改成已安装即可
删除则更简单,先查询子树已安装个数,再子树修改直接清零就行了。
代码如下:
#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#define lson root<<1
#define rson root<<1|1
using namespace std;

struct node
{
    int l,r,sum,lazy;
} tr[400040];

int fa[100010],son[100010],deep[100010],size[100010],id[100010],top[100010],cnt;
vector<int> g[100010];

void push_up(int root)
{
    tr[root].sum=tr[lson].sum+tr[rson].sum;
}

void push_down(int root)
{
    int mid=(tr[root].l+tr[root].r)>>1;
    tr[lson].sum=tr[root].lazy*(mid-tr[root].l+1);
    tr[lson].lazy=tr[root].lazy;
    tr[rson].sum=tr[root].lazy*(tr[root].r-mid);
    tr[rson].lazy=tr[root].lazy;
    tr[root].lazy=-1;
}

void build(int root,int l,int r)
{
    if(l==r)
    {
        tr[root].l=l;
        tr[root].r=r;
        tr[root].sum=0;
        tr[root].lazy=-1;
        return ;
    }
    tr[root].l=l;
    tr[root].r=r;
    tr[root].lazy=-1;
    int mid=(l+r)>>1;
    build(lson,l,mid);
    build(rson,mid+1,r);
    push_up(root);
}

void update(int root,int l,int r,int val)
{
    if(l==tr[root].l&&tr[root].r==r)
    {
        tr[root].sum=(tr[root].r-tr[root].l+1)*val;
        tr[root].lazy=val;
        return ;
    }
    if(~tr[root].lazy)
    {
        push_down(root);
    }
    int mid=(tr[root].l+tr[root].r)>>1;
    if(l>mid)
    {
        update(rson,l,r,val);
    }
    else
    {
        if(r<=mid)
        {
            update(lson,l,r,val);
        }
        else
        {
            update(lson,l,mid,val);
            update(rson,mid+1,r,val);
        }
    }
    push_up(root);
}

int query(int root,int l,int r)
{
    if(tr[root].l==l&&tr[root].r==r)
    {
        return tr[root].sum;
    }
    if(~tr[root].lazy)
    {
        push_down(root);
    }
    int mid=(tr[root].l+tr[root].r)>>1;
    if(mid<l)
    {
        return query(rson,l,r);
    }
    else
    {
        if(mid>=r)
        {
            return query(lson,l,r);
        }
        else
        {
            return query(lson,l,mid)+query(rson,mid+1,r);
        }
    }
}

void dfs1(int now,int f,int dep)
{
    fa[now]=f;
    size[now]=1;
    deep[now]=dep;
    int maxson=-1;
    for(int i=0; i<g[now].size(); i++)
    {
        if(g[now][i]==f)
        {
            continue;
        }

        dfs1(g[now][i],now,dep+1);
        size[now]+=size[g[now][i]];
        if(size[g[now][i]]>maxson)
        {
            maxson=size[g[now][i]];
            son[now]=g[now][i];
        }
    }
}

void dfs2(int now,int topf)
{
    id[now]=++cnt;
    top[now]=topf;
    if(!son[now])
    {
        return ;
    }
    dfs2(son[now],topf);
    for(int i=0; i<g[now].size(); i++)
    {
        if(g[now][i]==fa[now]||g[now][i]==son[now])
        {
            continue;
        }
        dfs2(g[now][i],g[now][i]);
    }
}

void path_update(int u,int v,int val)
{
    while(top[u]!=top[v])
    {
        if(deep[top[u]]<deep[top[v]])
        {
            swap(u,v);
        }
        update(1,id[top[u]],id[u],val);
        u=fa[top[u]];
    }
    if(deep[u]>deep[v])
    {
        swap(u,v);
    }
    update(1,id[u],id[v],val);
}

int path_query(int u,int v)
{
    int ans1=0,ans2=0;
    while(top[u]!=top[v])
    {
        if(deep[top[u]]<deep[top[v]])
        {
            swap(u,v);
        }
        ans1+=query(1,id[top[u]],id[u]);
        ans2+=id[u]-id[top[u]]+1;
        u=fa[top[u]];
    }
    if(deep[u]>deep[v])
    {
        swap(u,v);
    }
    ans1+=query(1,id[u],id[v]);
    ans2+=id[v]-id[u]+1;
    return ans2-ans1;
}

void sub_update(int u,int val)
{
    update(1,id[u],id[u]+size[u]-1,val);
}

int sub_query(int u)
{
    return query(1,id[u],id[u]+size[u]-1);
}

int main()
{
    int n,m;
    scanf("%d",&n);
    for(int i=1; i<=n-1; i++)
    {
        int tmp;
        scanf("%d",&tmp);
        g[tmp+1].push_back(i+1);
        g[i+1].push_back(tmp+1);
    }
    dfs1(1,0,1);
    dfs2(1,1);
    build(1,1,n);
    scanf("%d",&m);
    char c[20];
    while(m--)
    {
        int tmp;
        scanf("\n%s%d",c,&tmp);
        if(c[0]==i)
        {
            printf("%d\n",path_query(1,tmp+1));
            path_update(1,tmp+1,1);
        }
        if(c[0]==u)
        {
            printf("%d\n",sub_query(tmp+1));
            sub_update(tmp+1,0);
        }
    }
}

 

 

以上是关于洛谷 P2146 [NOI2015]软件包管理器 (树链剖分模板题)的主要内容,如果未能解决你的问题,请参考以下文章

洛谷 P2146 软件包管理器

Luogu P2146软件包管理器

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

[树链剖分][线段树] Luogu P2146 软件包管理器

[BZOJ4196][Noi2015]软件包管理器

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