【NOI2015 Day1】軟件包管理器

問題描述

    Linux用戶和OS X用戶一定對軟件包管理器不會陌生。通過軟件包管理器,你可以通過一行命令安裝某一個軟件包,然後軟件包管理器會幫助你從軟件源下載軟件包,同時自動解決所有的依賴(即下載安裝這個軟件包的安裝所依賴的其他軟件包),完成所有的配置。Debian/Ubuntu使用的apt-get,Fedora/CentOS使用的是yum,以及OS X下可用的homebrew都是優秀的軟件包管理器。
    你決定設計你自己的軟件包管理器。不可避免的,你要解決軟件包之間的依賴問題。如果軟件包A依賴軟件包B,那麼安裝軟件包B以前,必須先安裝軟件包B。同時,如果想要卸載軟件包B,則必須卸載軟件包A。現在你已經獲得了所有的軟件包之間的依賴關係。而且,由於你之前的工作,除0號軟件包以外,在你的管理器當中的軟件包都會依賴一個且僅一個軟件包,而0號軟件包不依賴任何一個軟件包。依賴關係不存在環(若有m(m>=2)個軟件包A1,A2,A2依賴A3,...,Am,其中A1依賴A2,A2依賴A3,A3依賴A4,……,Am-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

樣例輸入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
樣例輸出

樣例輸出1:
3
1
3
2
3

樣例輸出2:
1
3
2
1
3
1
1
1
0
1

題解

樹鏈剖分+DFS序。安裝從當前節點到根節點的軟件包直接用樹剖處理。
由於樹剖也是在DFS的過程中實現的,尋找輕重鏈只是改變了子節點遍歷的順序,一棵子樹仍然可以用DFS序轉化成一個區間,因此卸載操作直接用DFS序+線段樹處理即可。

代碼

#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
const int maxn=1e5+5;
int a,n,q,cnt,tot,Last[maxn];
int l[maxn],r[maxn],id[maxn],fa[maxn],dep[maxn],siz[maxn],son[maxn],top[maxn],maxx[maxn];
string op;
struct node{
    int sum,lazy;
}tree[8*maxn];
struct node_{
    int Next,End;
}edge[maxn];
inline int input()
{
    char t=getchar();
    int x=0,flag=0;
    while(t<48||t>57)
    {
        if(t=='-') flag=1;
        t=getchar();
    }
    for(;t>=48&&t<=57;t=getchar()) x=x*10+t-48;
    return flag?-x:x;
}
inline void output(int x)
{
    if(x<0) putchar('-'),x=-x;
    if(x>9) output(x/10);
    putchar(x%10+48);
}
void save(int x,int y)
{
    edge[++cnt].End=y;
    edge[cnt].Next=Last[x],Last[x]=cnt;
}
void getsiz(int x,int f)
{
    siz[x]=1,fa[x]=f,dep[x]=dep[fa[x]]+1;
    int temp=Last[x];
    while(temp)
    {
        int y=edge[temp].End;
        getsiz(y,x),siz[x]+=siz[y];
        if(siz[y]>maxx[x]) maxx[x]=siz[y],son[x]=y;
        temp=edge[temp].Next;
    }
}
void getway(int x,int anc)
{
    if(!x) return;
    l[x]=id[x]=++tot,top[x]=anc,getway(son[x],anc);
    int temp=Last[x];
    while(temp)
    {
        int y=edge[temp].End;
        if(y!=son[x]) getway(y,y);
        temp=edge[temp].Next;
    }
    r[x]=tot;
}
void build(int p,int ll ,int rr)
{
    tree[p].sum=0,tree[p].lazy=-1;
    if(ll<rr)
    {
        int mid=(ll+rr)>>1;
        build(p<<1,ll,mid),build(p<<1|1,mid+1,rr);
    }
}
void putdown(int p,int ll,int rr)
{
    if(ll==rr) return;
    int mid=(ll+rr)>>1;
    tree[p<<1].lazy=tree[p].lazy;
    tree[p<<1].sum=(mid-ll+1)*tree[p].lazy;
    tree[p<<1|1].lazy=tree[p].lazy;
    tree[p<<1|1].sum=(rr-mid)*tree[p].lazy;
    tree[p].lazy=-1;
}
int getsum(int p,int ll,int rr,int x,int y)
{
    if(tree[p].lazy!=-1) putdown(p,ll,rr);
    if(ll>=x&&rr<=y) return tree[p].sum;
    int mid=(ll+rr)>>1,lsum=0,rsum=0;
    if(x<=mid&&y>=ll) lsum+=getsum(p<<1,ll,mid,x,y);
    if(y>mid&&x<=rr) rsum+=getsum(p<<1|1,mid+1,rr,x,y);
    return lsum+rsum;
}
void modify(int p,int ll,int rr,int x,int y,int t)
{
    if(tree[p].lazy!=-1) putdown(p,ll,rr);
    if(ll>=x&&rr<=y)
    {
        tree[p].lazy=t;
        tree[p].sum=(rr-ll+1)*tree[p].lazy;
        return;
    }
    int mid=(ll+rr)>>1;
    if(x<=mid&&y>=ll) modify(p<<1,ll,mid,x,y,t);
    if(y>mid&&x<=rr) modify(p<<1|1,mid+1,rr,x,y,t);
    tree[p].sum=tree[p<<1].sum+tree[p<<1|1].sum;
}
int query(int x,int y)
{
    int ans=0;
    while(top[x]!=top[y])
    {
        if(dep[top[x]]>dep[top[y]]) swap(x,y);
        ans+=getsum(1,1,tot,id[top[y]],id[y]);
        y=fa[top[y]];
    }
    if(dep[x]>dep[y]) swap(x,y);
    ans+=getsum(1,1,tot,id[x],id[y]);
    return ans;
}
void change(int x,int y)
{
    while(top[x]!=top[y])
    {
        if(dep[top[x]]>dep[top[y]]) swap(x,y);
        modify(1,1,tot,id[top[y]],id[y],1);
        y=fa[top[y]];
    }
    if(dep[x]>dep[y]) swap(x,y);
    modify(1,1,tot,id[x],id[y],1);
}
int main()
{
    n=input();
    for(int i=2;i<=n;i++) a=input()+1,save(a,i);
    getsiz(1,0),getway(1,1),build(1,1,tot);
    q=input();
    while(q--)
    {
        cin>>op,a=input()+1;
        if(op=="install")
        {
            output(dep[a]-query(1,a)),putchar('\n');
            change(1,a);
        }
        else
        {
            output(getsum(1,1,tot,l[a],r[a])),putchar('\n');
            modify(1,1,tot,l[a],r[a],0);
        }
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章