[NOI2015]软件包管理器

[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步操作中改变安装状态的软件包数。

solution

对于安装操作就是把该节点到根的路径中的每个节点变为1

对于删除操作就是把子树赋为0

树链剖分

#include<bits/stdc++.h>

using namespace std;

#define MAXN 1000010

inline int read()
{
    int f=1,x=0;
    char ch;
    do
    {
        ch=getchar();
        if(ch=='-') f=-1;
    }while(ch<'0'||ch>'9');
    do
    {
        x=(x<<3)+(x<<1)+ch-'0';
        ch=getchar();
    }while(ch>='0'&&ch<='9');
    return f*x;
}

struct node
{
    int to;
    int next;
};

int n;
node g[MAXN*2];
int head[MAXN],cnt;
int fa[MAXN],tot[MAXN],son[MAXN],dep[MAXN];
int top[MAXN],num[MAXN],h=0;
int add[MAXN*4]={-1};

inline void addedge(int a,int b)
{
    ++cnt;g[cnt].to=b;g[cnt].next=head[a];head[a]=cnt;return;
}

inline void dfs(int x,int f)
{
    son[x]=0;tot[x]=1;
    for(int i=head[x];i;i=g[i].next)
    {
        int v=g[i].to;
        if(v!=f)
        {
            fa[v]=x;
            dep[v]=dep[x]+1;
            dfs(v,x);
            if(tot[v]>tot[son[x]]) son[x]=v;
            tot[x]+=tot[v];
        }
    }
    return;
}

inline void dfs2(int x,int now)
{
    top[x]=now;num[x]=++h;
    if(son[x]) dfs2(son[x],now);
    for(int i=head[x];i;i=g[i].next)
    {
        int v=g[i].to;
        if(v!=son[x]&&v!=fa[x]) dfs2(v,v);
    }
}

struct s_tree
{
    int l;
    int r;
    int sum;
    inline int mid()
    {
        return(l+r)>>1;
    }
}tree[MAXN<<2];

#define lc o<<1
#define rc o<<1|1

inline void build(int o,int l,int r)
{
    tree[o].l=l;tree[o].r=r;tree[o].sum=0;
    if(l==r) return;
    else
    {
        int mid=tree[o].mid();
        build(lc,l,mid);
        build(rc,mid+1,r);
    }
}

inline void pushdown(int o)
{
    add[lc]=add[o];
    add[rc]=add[o];
    tree[lc].sum=(tree[lc].r-tree[lc].l+1)*add[o];
    tree[rc].sum=(tree[rc].r-tree[rc].l+1)*add[o];
    add[o]=-1;
}

inline void update(int o,int x,int y,int z)
{
    int l=tree[o].l,r=tree[o].r;
    if(x<=l&&y>=r)
    {
        add[o]=z;
        tree[o].sum=(tree[o].r-tree[o].l+1)*add[o];
        return;
    }
    else
    {
        if(add[o]!=-1) pushdown(o);
        if(x>r||y<l) return;
        update(lc,x,y,z);
        update(rc,x,y,z);
        tree[o].sum=tree[lc].sum+tree[rc].sum; 
    }
}

inline int query(int o,int x,int y)
{
    int l=tree[o].l,r=tree[o].r;
    if(x<=l&&y>=r) return tree[o].sum;
    else
    {
        if(x>r||y<l) return 0;
        if(add[o]!=-1) pushdown(o);
        return query(lc,x,y)+query(rc,x,y);
    }
}

inline void change(int a,int b)
{
    int ta=top[a],tb=top[b];
    while(ta!=tb)
    {
        if(dep[ta]<dep[tb]) swap(ta,tb),swap(a,b);
        update(1,num[ta],num[a],1);
        a=fa[ta];ta=top[a];
    }
    if(a==b) update(1,num[a],num[b],1);
    else{
        if(dep[a]<dep[b]) swap(a,b);
        update(1,num[b],num[a],1);
    }
}

int main()
{
    n=read();
    for(int i=1;i<n;i++)
    {
        int x=read();x++;
        addedge(x,i+1);
        addedge(i+1,x);
    }
    fa[1]=0;dep[1]=1;
    dfs(1,0);
    dfs2(1,1);
    build(1,1,h);
    int q=read();
    for(int i=1;i<=q;i++)
    {
        string opt;cin>>opt;int x=read();x++;
        if(opt[0]=='i')
        {
            int ans1=query(1,num[1],num[x]);
            change(1,x);
            int ans2=query(1,num[1],num[x]);
            printf("%d\n",abs(ans2-ans1));
        }
        else
        {
            int ans1=query(1,num[x],num[x]+tot[x]-1);
            update(1,num[x],num[x]+tot[x]-1,0);
            int ans2=query(1,num[x],num[x]+tot[x]-1);
            printf("%d\n",abs(ans2-ans1));
        }
    }
}

猜你喜欢

转载自www.cnblogs.com/wlzs1432/p/9370877.html