1. 程式人生 > >【NOI2015】軟件包管理器

【NOI2015】軟件包管理器

vector 優秀 ubunt case 必須 包含 int all else

題目描述

Linux用戶和OSX用戶一定對軟件包管理器不會陌生。通過軟件包管理器,你可以通過一行命令安裝某一個軟件包,然後軟件包管理器會幫助你從軟件源下載軟件包,同時自動解決所有的依賴(即下載安裝這個軟件包的安裝所依賴的其它軟件包),完成所有的配置。ebian/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步操作中改變安裝狀態的軟件包數。

輸入輸出樣例

輸入樣例#1:
7
0 0 0 1 1 5
5
install 5
install 6
uninstall 1
install 4
uninstall 0
輸出樣例#1:
3
1
3
2
3
輸入樣例#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
輸出樣例#2:
1
3
2
1
3
1
1
1
0
1

說明

【樣例說明 1】

技術分享

一開始所有的軟件包都處於未安裝狀態。

安裝5號軟件包,需要安裝0,1,5三個軟件包。

之後安裝6號軟件包,只需要安裝6號軟件包。此時安裝了0,1,5,6四個軟件包。

卸載1號軟件包需要卸載1,5,6三個軟件包。此時只有0號軟件包還處於安裝狀態。

之後安裝4號軟件包,需要安裝1,4兩個軟件包。此時0,1,4處在安裝狀態。最後,卸載0號軟件包會卸載所有的軟件包。`

【數據範圍】

技術分享

【時限1s,內存512M】

題解

裸的樹鏈剖分+線段樹。樹上(指題目給的樹)每個結點有安裝和未安裝兩種狀態,對應計數1和0。樹鏈剖分到線段樹後,維護計數的和。

安裝操作即把節點x到根的路徑上所有節點的計數改為1,統計更改了多少節點並輸出。

刪除操作即把節點x及它的所有後代節點計數改為0,統計更改了多少節點並輸出。

#include <iostream>
#include <string>
#include <vector>
#define maxn 100010
using namespace std;
int n, m;
namespace seg
{
struct node
{
    int ln, rn, mn;
    int len;
    int cnt, mark;
};
node nds[maxn * 4];
void push_down(int p)
{
    if (nds[p].mark != -1 && nds[p].len > 1)
        nds[p * 2].mark = nds[p * 2 + 1].mark = nds[p].mark;
    nds[p].mark = -1;
}
void pull_up(int p)
{
    if (nds[p].mark != -1)
        nds[p].cnt = nds[p].mark * nds[p].len;
    else if (nds[p].len > 1)
        nds[p].cnt = nds[p * 2].cnt + nds[p * 2 + 1].cnt;
}
void init(int l, int r, int p = 1)
{
    node &nd = nds[p];
    nd.ln = l;
    nd.rn = r;
    nd.mn = (l + r) / 2;
    nd.len = r - l + 1;
    nd.cnt = 0;
    nd.mark = -1;
    if (l != r)
    {
        init(nd.ln, nd.mn, p * 2);
        init(nd.mn + 1, nd.rn, p * 2 + 1);
    }
}
void set(int l, int r, int val, int p = 1)
{
    node &nd = nds[p];
    if (nd.ln == l && nd.rn == r)
    {
        nd.mark = val;
    }
    else
    {
        push_down(p);
        if (l <= nd.mn)
            set(l, min(nd.mn, r), val, p * 2);
        else
            pull_up(p * 2);
        if (nd.mn + 1 <= r)
            set(max(l, nd.mn + 1), r, val, p * 2 + 1);
        else
            pull_up(p * 2 + 1);
    }
    pull_up(p);
}
int query(int l, int r, int p = 1)
{
    node &nd = nds[p];
    if (nd.mark != -1)
    {
        return nd.mark * (r - l + 1);
    }
    else if (nd.ln == l && nd.rn == r)
    {
        return nd.cnt;
    }
    else
    {
        int ans = 0;
        if (l <= nd.mn)
            ans += query(l, min(nd.mn, r), p * 2);
        if (nd.mn + 1 <= r)
            ans += query(max(l, nd.mn + 1), r, p * 2 + 1);
        return ans;
    }
}
}
namespace tree
{
int parent[maxn];
vector<int> child[maxn];
void add_child(int p, int c)
{
    parent[c] = p;
    child[p].push_back(c);
}

int depth[maxn], size[maxn], heavy[maxn];
void dfs1(int k = 0, int d = 0)
{
    size[k] = 1;
    depth[k] = d;

    heavy[k] = -1;
    int max_size = 0;
    for (int i = 0; i < child[k].size(); ++i)
    {
        dfs1(child[k][i], d + 1);
        size[k] += size[child[k][i]];

        if (max_size < size[child[k][i]])
        {
            max_size = size[child[k][i]];
            heavy[k] = child[k][i];
        }
    }
}

int top[maxn], hash[maxn];
int cnt = 1;
void dfs2(int k = 0)
{
    hash[k] = cnt++;
    if (child[k].size())
    {
        top[heavy[k]] = top[k];
        dfs2(heavy[k]);

        for (int i = 0; i < child[k].size(); ++i)
        {
            if (child[k][i] != heavy[k])
            {
                top[child[k][i]] = child[k][i];
                dfs2(child[k][i]);
            }
        }
    }
}

int install(int k)
{
    int ans = 0;
    while (true)
    {
        ans += (hash[k] - hash[top[k]] + 1) - seg::query(hash[top[k]], hash[k]);
        seg::set(hash[top[k]], hash[k], 1);
        if (top[k] == 0)
            break;
        k = parent[top[k]];
    }
    return ans;
}
int uninstall(int k)
{
    int ans = seg::query(hash[k], hash[k] + size[k] - 1);
    seg::set(hash[k], hash[k] + size[k] - 1, 0);
    return ans;
}
}
int main()
{
    cin >> n;

    int a;
    for (int i = 1; i <= n - 1; ++i)
    {
        cin >> a;
        tree::add_child(a, i);
    }

    tree::dfs1();
    tree::dfs2();
    seg::init(1, n);

    cin >> m;
    string str;
    while (m--)
    {
        cin >> str >> a;
        switch (str[0])
        {
        case i:
            cout << tree::install(a) << endl;
            break;
        case u:
            cout << tree::uninstall(a) << endl;
            break;
        }
    }
    return 0;
}

【NOI2015】軟件包管理器