NOI2015 軟體包管理器(巧用線段樹)

2022-02-02 16:25:56 字數 1586 閱讀 5556

原題鏈結

線段樹基本板子的可塑性其實非常強悍,針對不同的題目要求只要稍作修改就可以發揮不同的作用。這道題讓我更深刻地理解了這一點。

本題和普通的樹鏈剖分+線段樹最大的區別在於它的每個結點並不儲存乙個數值,而是只有兩種狀態:安裝與未安裝。針對這一特點,我們對線段樹的板子做以下修改即可:

lazy標記:由於現在每個節點只有兩種狀態,\(lazy\)標記也只有兩種數值就夠了,比如\(1\)代表該區間所有軟體全部被安裝,\(-1\)代表該區間所有軟體全部沒有被安裝。

pushdown操作:之前\(pushdown\)僅僅把父節點的\(lazy\)標記下放即可,但現在\(lazy\)標記有兩種,所以下放之前應當先判斷:\(lazy\)標記為\(1\)則代表全部安裝,那麼就應當把子節點的安裝數量變為區間內總節點數;\(lazy\)標記為\(1\)則代表全部解除安裝,那麼就應當把子節點的安裝數量變為\(0\)。

update操作:之前傳參時傳遞的是向該區間內加的數,現在則應更改為操作模式,即解除安裝還是安裝?安裝則把\(lazy\)標記記為\(1\),把子節點的安裝數量變為區間內總節點數;解除安裝則把\(lazy\)標記記為\(-1\),把子節點的安裝數量變為\(0\)。

其餘操作均保持不變

#includeusing namespace std;

const int maxn=100000+3;

int head[maxn],tot,dep[maxn],size[maxn],son[maxn],top[maxn],n,q,fa[maxn],dfn[maxn],dfn_clock;

struct edgee[maxn<<1];

struct nodetree[maxn<<2];

void add(int a,int b)

void dfs(int u,int father)

}void get_top(int u,int t)

}void build(int rt,int l,int r)

void renew(int rt)

void push_down(int rt)

if(tree[rt].lazy==-1)

tree[rt].lazy=0;

}void update(int rt,int s,int t,int mode)

push_down(rt);

int mid=tree[rt].l+tree[rt].r>>1;

if(s<=mid) update(rt<<1,s,t,mode);

if(t>mid) update(rt<<1|1,s,t,mode);

renew(rt);

}int query(int rt,int s,int t)

int ask(int u)

ans+=query(1,1,dfn[u]);

return ans;

}void treeadd(int u,int mode)

update(1,1,dfn[u],mode);

}int main(){

scanf("%d",&n);

for(int i=1;i幸甚至哉,歌以詠志。

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...