題目
一道樹剖的變形題
跟普通樹剖不一樣的是,每次安裝/ 解除安裝軟體後,需要把區間中的值統一改為 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 ...