[NOI2015]软件包管理器 树链剖分 + 线段树

Description

 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,……,Am−1依赖Am,而Am依赖A1,则称这m个软件包的依赖关系构成环),当然也不会有一个软件包依赖自己。
现在你要为你的软件包管理器写一个依赖解决程序。根据反馈,用户希望在安装和卸载某个软件包时,快速地知道这个操作实际上会改变多少个软件包的安装状态(即安装操作会安装多少个未安装的软件包,或卸载操作会卸载多少个已安装的软件包),你的任务就是实现这个部分。注意,安装一个已安装的软件包,或卸载一个未安装的软件包,都不会改变任何软件包的安装状态,即在此情况下,改变安装状态的软件包数为0。
 

Input

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

随后一行包含n−1个整数,相邻整数之间用单个空格隔开,分别表示1,2,3,…,n−2,n−1号软件包依赖的软件包的编号。
接下来一行包含1个正整数q,表示询问的总数。
之后q行,每行1个询问。询问分为两种:
installx:表示安装软件包x
uninstallx:表示卸载软件包x
你需要维护每个软件包的安装状态,一开始所有的软件包都处于未安装状态。对于每个操作,你需要输出这步操作会改变多少个软件包的安装状态,随后应用这个操作(即改变你维护的安装状态)。
 

Output

输出文件包括q行。

输出文件的第i行输出1个整数,为第i步操作中改变安装状态的软件包数。
 
// luogu-judger-enable-o2
#include <bits/stdc++.h>
#define setIO(s) freopen(s".in","r",stdin) 
#define maxn 100002 
using namespace std;
int read()
{
    int f=1,x=0;
    char ss=getchar();
    while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}
    while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}
    return f*x;
}

void print(int x)
{
    if(x<0){putchar('-');x=-x;}
    if(x>9)print(x/10);
    putchar(x%10+'0');
}
namespace Seg
{
    #define lson (x << 1)
    #define rson ((x << 1) | 1) 
    int sumv[maxn << 2], lazy[maxn << 2]; 
    void mark_tag(int l, int r, int x, int delta)
    {     
        sumv[x] = (r - l + 1) * delta, lazy[x] = delta; 
    }
    void pushdown(int l, int r, int x)
    {   
        if(lazy[x] == -1) return ; 
        int mid = (l + r) >> 1; 
        if(mid >= l) mark_tag(l, mid, lson, lazy[x]); 
        if(mid < r) mark_tag(mid + 1, r, rson, lazy[x]); 
        lazy[x] = -1; 
    }
    int query(int l, int r, int x, int L, int R)
    {
        if(l >= L && r <= R)
        {
            return sumv[x]; 
        }
        pushdown(l, r, x); 
        int mid = (l + r) >> 1; 
        int t = 0; 
        if(L <= mid)  t += query(l, mid, lson, L, R); 
        if(R > mid) t += query(mid + 1, r, rson, L, R); 
        return t; 
    }
    void update(int l, int r, int x, int L, int R, int d)
    {
        if(l >= L && r <= R)
        {
            mark_tag(l, r, x, d); 
            return ; 
        }
        pushdown(l, r, x); 
        int mid = (l + r) >> 1; 
        if(L <= mid) update(l, mid, lson, L, R, d); 
        if(R > mid) update(mid + 1, r, rson, L, R, d); 
        sumv[x] = sumv[lson] + sumv[rson]; 
    }
}; 
int hd[maxn], to[maxn], nex[maxn], fa[maxn], siz[maxn], top[maxn], hson[maxn], dep[maxn]; 
int st[maxn], ed[maxn], dfn[maxn]; 
int edges, n, Q, root = 1, tim; 
char str[100]; 
void add(int u, int v)
{
    nex[++edges] = hd[u], hd[u] = edges, to[edges] = v; 
}   
void dfs1(int u)
{
    siz[u] = 1, dep[u] = dep[fa[u]] + 1;  
    for(int i = hd[u]; i ; i = nex[i])
    {
        dfs1(to[i]), siz[u] += siz[to[i]]; 
        if(siz[to[i]] > siz[hson[u]]) hson[u] = to[i]; 
    }
}
void dfs2(int u, int tp)
{
    dfn[u] = ++tim, top[u] = tp;
    st[u] = tim; 
    if(hson[u]) 
        dfs2(hson[u], tp);  
    for(int i = hd[u]; i ; i = nex[i])
    {
        if(to[i] != hson[u]) dfs2(to[i], to[i]); 
    }
    ed[u] = tim; 
}
int lookup(int x)
{
    int t = 0; 
    while(x)
    {
        t += Seg :: query(1, n, 1, dfn[top[x]], dfn[x]); 
        Seg :: update(1, n, 1, dfn[top[x]], dfn[x], 1); 
        x = fa[top[x]]; 
    }
    return t; 
} 
int main()
{
   //  setIO("input"); 
    n=read();  
    for(int i = 2; i <= n; ++i)
    {
        fa[i]=read(), ++fa[i], add(fa[i], i);            
    }
    dfs1(1), dfs2(1, 1);      
    memset(Seg::lazy, -1, sizeof(Seg :: lazy)); 
    Q=read(); 
    while(Q--)
    {     
        int u; 
        scanf("%s",str);
        u=read(); 
        u+=1; 
        if(str[0] == 'i') 
        {
            print(dep[u] - lookup(u)); 
            printf("\n"); 
        } 
        if(str[0] == 'u') 
        {
            print(Seg :: query(1, n, 1, st[u], ed[u])); 
            Seg :: update(1, n, 1, st[u], ed[u], 0);
            printf("\n");  
        }
    }
    return 0; 
}

  

转载于:https://www.cnblogs.com/guangheli/p/10994092.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值