• [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("
    "); 
            } 
            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("
    ");  
            }
        }
        return 0; 
    }
    

      

  • 相关阅读:
    atitit...触发器机制 ltrigger mechanism sumup .的总结O8f
    atitit. 集合groupby 的实现(2)---自定义linq查询--java .net php
    atitit. groupby linq的实现(1)-----linq框架选型 java .net php
    atitit.j2ee 1.5 1.6 的不同跟 Servlet 3.0新特性总结
    Atitit. 常用街机系统and 模拟器总结 snk neo geo cps mame sfc smc
    atitit. access token是什么??微信平台公众号开发access_token and Web session保持状态机制
    atitit.二进制数据无损转字符串网络传输
    atitit.压缩算法 ZLib ,gzip ,zip 最佳实践 java .net php
    Atitit.现实生活中最好使用的排序方法-----ati排序法总结
    atitit.修复xp 操作系统--重装系统--保留原来文件不丢失
  • 原文地址:https://www.cnblogs.com/guangheli/p/10994092.html
Copyright © 2020-2023  润新知