NOI2015 Day1 T2 軟件包管理器 樹鏈剖分

NKOJ3423 NOI2015 軟件包管理器

時間限制 : 20000 MS 空間限制 : 524288 KB
問題描述

    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。

輸入格式

    輸入文件的第1行包含1個整數n,表示軟件包的總數。軟件包從0開始編號。
    隨後一行包含n-1個整數,相鄰整數之間用單個空格隔開,分別表示1,2,3,...,n-2,n-1號軟件包依賴的軟件包編號。
    接下來一行包含1個整數q,表示詢問的總數。
    之後的q行,每行1個詢問。詢問分爲兩種:
    ●install x:表示安裝軟件包x
    ●uninstall x:表示卸載軟件包x
    你需要維護每個軟件包的安裝狀態,一開始所有的軟件包都處於未安裝狀態,對於每個操作,你需要輸出這步操作會改變多少個軟件包的安裝狀態,隨後應用這個操作(即改變你維護的安裝狀態)。

輸出格式

    輸出文件包括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

數據範圍

n<=100000,q<=100000


題目就是求一條鏈上染色的點的個數、一棵子樹上染色的點的個數,同時支持給一條鏈染色、給一棵子樹染色。

鏈用樹鏈剖分處理,子樹用DFS序處理。由於樹剖的預處理就是DFS,所以順帶就把DFS序求了出來,新的編號不僅滿足重鏈剖分的性質,而且滿足DFS序的性質,也就是說,一條重鏈和一棵子樹上的點,新的編號都必定是連續的。剩下的就只是一個線段樹區間修改問題了。


#include<stdio.h>
#include<vector>
#include<algorithm>
#define MAXN 100005
#define MAXT 400005
using namespace std;

vector<int>G[MAXN];
int N;

int dep[MAXN],Hson[MAXN],Size[MAXN],fa[MAXN];
void GetSon(int x,int f)
{
    dep[x]=dep[f]+1;fa[x]=f;Size[x]=1;
    int i,y,Max=0;
    for(i=0;i<G[x].size();i++)
    {
        y=G[x][i];
        GetSon(y,x);
        Size[x]+=Size[y];
        if(Size[y]>Max)Max=Size[y],Hson[x]=y;
    }
}

int lab,id[MAXN],In[MAXN],Out[MAXN],anc[MAXN];
void Connect(int x,int aa)
{
    id[x]=In[x]=++lab;anc[x]=aa;
    int i,y;
    if(Hson[x])Connect(Hson[x],aa);
    for(i=0;i<G[x].size();i++)
    {
        y=G[x][i];
        if(y!=Hson[x])Connect(y,y);
    }
    Out[x]=lab;
}

int tot,rs[MAXT],ls[MAXT],sum[MAXT],lazy[MAXT],a[MAXT],b[MAXT];

void Update(int p){sum[p]=sum[ls[p]]+sum[rs[p]];}

void Putdown(int p)
{
    int t=lazy[p];
    lazy[p]=0;lazy[ls[p]]=lazy[rs[p]]=t;
    if(t==1)sum[rs[p]]=b[rs[p]]-a[rs[p]]+1,sum[ls[p]]=b[ls[p]]-a[ls[p]]+1;
    else sum[ls[p]]=sum[rs[p]]=0;
}

int Build(int x,int y)
{
    int p=++tot,mid=x+y>>1;
    a[p]=x;b[p]=y;
    if(x==y)return p;
    ls[p]=Build(x,mid);
    rs[p]=Build(mid+1,y);
    return p;
}

int GetSum(int p,int x,int y)
{
    if(lazy[p])Putdown(p);
    if(a[p]>=x&&b[p]<=y)return sum[p];
    int lsum=0,rsum=0,mid=a[p]+b[p]>>1;
    if(x<=mid)lsum=GetSum(ls[p],x,y);
    if(y>mid)rsum=GetSum(rs[p],x,y);
    return lsum+rsum;
}

void Modify(int p,int x,int y,int k)
{
    if(lazy[p])Putdown(p);
    if(a[p]>=x&&b[p]<=y)
    {
        if(k==1)sum[p]=b[p]-a[p]+1;
        else sum[p]=0;
        lazy[p]=k;
        return;
    }
    int mid=a[p]+b[p]>>1;
    if(x<=mid)Modify(ls[p],x,y,k);
    if(y>mid)Modify(rs[p],x,y,k);
    Update(p);
}

int Qsum(int x,int y)
{
    int ans=0;
    while(anc[x]!=anc[y])
    {
        if(dep[anc[x]]<dep[anc[y]])swap(x,y);
        ans+=GetSum(1,id[anc[x]],id[x]);
        x=fa[anc[x]];
    }
    if(dep[x]>dep[y])swap(x,y);
    ans+=GetSum(1,id[x],id[y]);
    return ans;
}

void Qmodify(int x,int y)
{
    while(anc[x]!=anc[y])
    {
        if(dep[anc[x]]<dep[anc[y]])swap(x,y);
        Modify(1,id[anc[x]],id[x],1);
        x=fa[anc[x]];
    }
    if(dep[x]>dep[y])swap(x,y);
    Modify(1,id[x],id[y],1);
}

void Init()
{
    GetSon(1,0);
    Connect(1,1);
    Build(1,N);
}

int main()
{
    int i,x;
    char op[12];

    scanf("%d",&N);
    for(i=2;i<=N;i++)scanf("%d",&x),G[x+1].push_back(i);

    Init();

    int Q;
    scanf("%d",&Q);
    while(Q--)
    {
        scanf("%s%d",op,&x);x++;
        if(op[0]=='i')
        {
            printf("%d\n",dep[x]-Qsum(1,x));
            Qmodify(1,x);
        }
        else
        {
            printf("%d\n",GetSum(1,In[x],Out[x]));
            Modify(1,In[x],Out[x],2);
        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章