Noi2015 軟體包管理器 樹鏈剖分

2021-08-20 05:39:02 字數 2915 閱讀 6846

time limit: 10 sec  

memory limit: 512 mb

submit: 2411  

solved: 1397 [

submit][

status][

discuss]

你決定設計你自己的軟體包管理器。不可避免地,你要解決軟體包之間的依賴問題。如果軟體包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。

輸入檔案的第1行包含1個正整數n,表示軟體包的總數。軟體包從0開始編號。

隨後一行包含n−1個整數,相鄰整數之間用單個空格隔開,分別表示1,2,3,…,n−2,n−1號軟體包依賴的軟體包的編號。

接下來一行包含1個正整數q,表示詢問的總數。

之後q行,每行1個詢問。詢問分為兩種:

installx:表示安裝軟體包x

uninstallx:表示解除安裝軟體包x

你需要維護每個軟體包的安裝狀態,一開始所有的軟體包都處於未安裝狀態。對於每個操作,你需要輸出這步操作會改變多少個軟體包的安裝狀態,隨後應用這個操作(即改變你維護的安裝狀態)。

輸出檔案包括q行。

輸出檔案的第i行輸出1個整數,為第i步操作中改變安裝狀態的軟體包數。 7

0 0 0 1 1 5

5install 5

install 6

uninstall 1

install 4

uninstall 031

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

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

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

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

之後安裝 4 號軟體包,需要安裝 1,4 兩個軟體包。此時 0,1,4 處在安裝狀態。

最後,解除安裝 0 號軟體包會解除安裝所有的軟體包。

n=100000

q=100000

每次安裝,相當於root到它這條路徑全部安裝。每次解除安裝,相當於它子樹全解除安裝。

於是用樹鏈剖分,線段樹上維護區間和(單點值只有0或1,即未安裝或已安裝)。

#include #include #define n 100010

using namespace std;

struct edge e[n];

int head[n], fa[n], son[n], size[n], tp[n], st[n], ed[n], rid[n], dep[n];

int n, q, cnt = 1, dfn = 0;

inline void ins(int x, int y)

void dfs1(int x, int f, int d)

}void dfs2(int x, int top)

int lazy[n<<2], v[n<<2];

inline void pushdown0(int p, int l, int r, int mid)

inline void pushdown1(int p, int l, int r, int mid)

inline void update(int p, int l, int r)

int query(int p, int l, int r, int x, int y)

void change(int p, int l, int r, int x, int y, int key)

int mid = (l + r)>>1; if(!lazy[p]) pushdown0(p, l, r, mid); if(lazy[p] == 1) pushdown1(p, l, r, mid);

if(x <= mid) change(p<<1, l, mid, x, y, key);

if(mid + 1 <= y) change(p<<1|1, mid + 1, r, x, y, key);

update(p, l, r);

} inline int tree_find(int x)

return tot - ret;

}inline void tree_change(int x, int key)

}int main()

dfs1(0, 0, 1); dfs2(0, 0);

scanf("%d", &q);

for(int i = 1; i <= q; ++i)

int ans = tree_find(x);

printf("%d\n", ans);

tree_change(x, 1);

}else

int tree_son = query(1, 1, n, st[x], ed[x]);

printf("%d\n", tree_son);

change(1, 1, n, st[x], ed[x], 0);

} }return 0;

}

樹鏈剖分真的是乙個優秀的演算法。

noi2015軟體包管理器

你決定設計你自己的軟體包管理器。不可避免的,你要解決軟體包之間的依賴關係。如果a依賴b,那麼安裝a之前需安裝b,解除安裝b之前須解除安裝a。0號軟體包不依賴任何軟體包。依賴關係不存在環 包括自環 你的任務是,求出每次安裝 刪除操作會改變多少個包的狀態。安裝乙個已安裝的軟體包,或者解除安裝乙個未安裝的...

Noi2015 軟體包管理器

time limit 10 sec memory limit 512 mb 你決定設計你自己的軟體包管理器。不可避免地,你要解決軟體包之間的依賴問題。如果軟體包a依賴軟體包b,那麼安裝軟體包a以前,必須先安裝軟體包b。同時,如果想要解除安裝軟體包b,則必須解除安裝軟體包a。現在你已經獲得了所有的軟體...

NOI2015 軟體包管理器

樹鏈剖分維護。1表示安裝的狀態,0表示沒有安裝的狀態。如果install就是把當前點到根的所有點都變成1,然後計算前後的 delta 如果uninstall呢,就是把自己的子樹變成0,答案也是前後的 delta 具體可以參照 不過我的 常數好大啊,跑得好慢。如下 include include in...