P2146 NOI2015 軟體包管理器 題解

2021-10-22 23:50:20 字數 3639 閱讀 1034

題目

一道樹剖的變形題

跟普通樹剖不一樣的是,每次安裝/ 解除安裝軟體後,需要把區間中的值統一改為 0/1

0/10/

1 。而這個也並不難實現

s um

[k

]sum[k]

sum[k]

表示區間 k

kk 中已安裝的軟體個數(1

11 的個數),並不需要再開乙個陣列維護 lazy-tag,可以理解為將求和和 lazy-tag 合併了

每次要將區間賦值 0/1

0/10/

1 時,就直接將 sum

[k

]sum[k]

sum[k]

賦值為 0/(

r−l+

1)

0/(r-l+1)

0/(r−l

+1),然後直接回溯。在訪問的時候遇到 sum

[k]=

0/(r

−l+1

)sum[k] = 0/(r-l+1)

sum[k]

=0/(

r−l+

1)時,就當做 lazy-tag 下放

關鍵**:

inline

void

push_down

(int k,

int l,

int r)

elseif(

!sum[k]

)// 反之亦然

sum[k<<1]

=sum[k<<1|

1]=0

;}void

modify

(int k,

int l,

int r,

int x,

int y,

int v)

// 將區間中所有元素賦值為v

push_down

(k,l,r)

;int mid=

(l+r)

>>1;

if(x<=mid)

modify

(k<<

1,l,mid,x,y,v);if

(midmodify

(k<<1|

1,mid+

1,r,x,y,v)

;push_up

(k);

}int

query

(int k,

int l,

int r,

int x,

int y,

int v)

// 詢問等於v的元素個數

push_down

(k,l,r)

;int mid=

(l+r)

>>

1,ret=0;

if(x<=mid)ret+

=query

(k<<

1,l,mid,x,y,v);if

(mid=query

(k<<1|

1,mid+

1,r,x,y,v)

;return ret;

}

解決了這個問題之後,剩下的就是模板樹剖啦

ps:**裡的節點編號為 1∼n

1\sim n

1∼n

#include

#include

#include

#include

using

namespace std;

const

int maxn=

100000+10

,maxm=

400000+10

;int sum[maxm]

,add[maxm]

;int s[maxn]

,id[maxn]

,son[maxn]

;int top[maxn]

,f[maxn]

,d[maxn]

;int n,m,idcnt;

vector <

int> e[maxn]

;inline

void

push_up

(int k)

inline

void

push_down

(int k,

int l,

int r)

elseif(

!sum[k]

) sum[k<<1]

=sum[k<<1|

1]=0

;}inline

intread()

while

(ch>=

'0'&& ch<=

'9')s=

(s<<3)

+(s<<1)

+(ch^48)

,ch=

getchar()

;return s*w;

}void

modify

(int k,

int l,

int r,

int x,

int y,

int v)

push_down

(k,l,r)

;int mid=

(l+r)

>>1;

if(x<=mid)

modify

(k<<

1,l,mid,x,y,v);if

(midmodify

(k<<1|

1,mid+

1,r,x,y,v)

;push_up

(k);

}int

query

(int k,

int l,

int r,

int x,

int y,

int v)

push_down

(k,l,r)

;int mid=

(l+r)

>>

1,ret=0;

if(x<=mid)ret+

=query

(k<<

1,l,mid,x,y,v);if

(mid=query

(k<<1|

1,mid+

1,r,x,y,v)

;return ret;

}void

dfs1

(int x,

int fa)

}void

dfs2

(int x,

int topp)

}int

ins(

int x)

// 將根節點到x的路徑上的軟體都裝上

ret+

=query(1

,1,n,id[1]

,id[x],0

);modify(1

,1,n,id[1]

,id[x],1

);return ret;

}int

del(

int x)

// 將子樹中已安裝的全部刪掉

intmain()

dfs1(1

,0);

dfs2(1

,1);

m=read()

;while

(m--

)return0;

}

P2146 NOI2015 軟體包管理器

很好的樹剖板子題 操作一 求點x到0的最短路徑 經過的結點個數 路徑上已安裝的軟體包的總個數,同時將經過的路徑上的所有點標記為已安裝。操作二 將子樹代表的那段存安裝包個數的區間清空 或者是說將其sum值賦值為0 此處為了實現標記已安裝和清空,我們用了乙個標記add add i 1 線段樹上的點i及其...

P2146 NOI2015 軟體包管理器

輸入格式 從檔案manager.in中讀入資料。輸入檔案的第1行包含1個整數n,表示軟體包的總數。軟體包從0開始編號。隨後一行包含n 1個整數,相鄰整數之間用單個空格隔開,分別表示1,2,3,n 2,n 1號軟體包依賴的軟體包的編號。接下來一行包含1個整數q,表示詢問的總數。之後q行,每行1個詢問。...

P2146 NOI2015 軟體包管理器

p2146 noi2015 軟體包管理器 樹鏈剖分 帶區間修改線段樹 install操作 該點到根之間修改成1 uni操作 該點及其子樹修改成0 每次操作時和上次的相減一下即可 include include include include using namespace std template ...