樹鏈剖分 BZOJ3589 動態樹

2022-05-28 02:51:10 字數 3210 閱讀 5689

time limit: 30 sec  memory limit: 1024 mb

submit: 543  solved: 193

[submit][status][discuss]

別忘了這是一棵動態樹, 每時每刻都是動態的. 小明要求你在這棵樹上維護兩種事件

事件0:

這棵樹長出了一些果子, 即某個子樹中的每個節點都會長出k個果子.

事件1:

小明希望你求出幾條樹枝上的果子數. 一條樹枝其實就是乙個從某個節點到根的路徑的一段. 每次小明會選定一些樹枝, 讓你求出在這些樹枝上的節點的果子數的和. 注意, 樹枝之間可能會重合, 這時重合的部分的節點的果子只要算一次.

第一行乙個整數n(1<=n<=200,000), 即節點數.

接下來n-1行, 每行兩個數字u, v. 表示果子u和果子v之間有一條直接的邊. 節點從1開始編號.

在接下來乙個整數nq(1<=nq<=200,000), 表示事件.

最後nq行, 每行開頭要麼是0, 要麼是1.

如果是0, 表示這個事件是事件0. 這行接下來的2個整數u, delta表示以u為根的子樹中的每個節點長出了delta個果子.

如果是1, 表示這個事件是事件1. 這行接下來乙個整數k(1<=k<=5), 表示這次詢問涉及k個樹枝. 接下來k對整數u_k, v_k, 每個樹枝從節點u_k到節點v_k. 由於果子數可能非常多, 請輸出這個數模2^31的結果.

對於每個事件1, 輸出詢問的果子數.

51 2

2 32 4

1 53

0 1 1

0 2 3

1 2 3 1 1 4

131 <= n <= 200,000, 1 <= nq <= 200,000, k = 5.

生成每個樹枝的過程是這樣的:先在樹中隨機找乙個節點, 然後在這個節點到根的路徑上隨機選乙個節點, 這兩個節點就作為樹枝的兩端.

by 佚名提供

樹剖模板題,不過注意只能加一次,所以可以打標記,一次詢問後記得清除標記

另外,怎麼對1<<31取模不懂

1 #include2 #include3 #include4 #include5

using

namespace

std;

6int

n,m,cnt,tot;

7struct

dtedge[400010

];10

struct

datatree[200010

];13

struct

segsegtree[800010

];16

int head[200010

];17

void add(int start,int

end)

22void dfs_weight(int

u)33}34

void dfs_build(int u,int

tp)42 tree[u].getout=tot;43}

44void up(int

pos)

48void update1(int pos,int

d)52

void update2(int pos,int d,int ll,int

rr)56

void down(int pos,int ll,int mid,int

rr)62

if(segtree[pos].tag1!=-1)67

}68void build(int pos,int ll,int

rr)73

int mid=(ll+rr)>>1

;74 build(pos<<1

,ll,mid);

75 build(pos<<1|1,mid+1

,rr);76}

77void change(int pl,int pr,int d,int pos,int ll,int

rr)84

int mid=(ll+rr)>>1;85

down(pos,ll,mid,rr);

86if(pr<=mid) change(pl,pr,d,pos<<1

,ll,mid);

87else

if(pl>mid) change(pl,pr,d,pos<<1|1,mid+1

,rr);

88else

92up(pos);93}

94void ask_some(int aa,int

bb)103

else

108}

109if(tree[aa].deep1,1,1

,n);

110else change(tree[bb].getin,tree[aa].getin,1,1,1

,n);

111}

112void add_val(int pl,int pr,int d,int pos,int ll,int

rr)118

int mid=(ll+rr)>>1

;119

down(pos,ll,mid,rr);

120if(pr<=mid) add_val(pl,pr,d,pos<<1

,ll,mid);

121else

if(pl>mid) add_val(pl,pr,d,pos<<1|1,mid+1

,rr);

122else

126up(pos);

127}

128int

main()

136 tree[1].deep=1

;137 dfs_weight(1

);138 dfs_build(1,1

);139 build(1,1

,n);

140 scanf("

%d",&m);

141int od=0,k=0

;142

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

150 printf("

%d\n

",segtree[1].ret&((1

<<31)-1));//

???編譯顯示溢位

151 update1(1,0

);152

}153

else

157}158

return0;

159 }

bzoj 3589 動態樹 (樹鏈剖分 線段樹)

time limit 30 sec memory limit 1024 mb submit 451 solved 155 submit status discuss 別忘了這是一棵動態樹,每時每刻都是動態的.小明要求你在這棵樹上維護兩種事件 事件0 這棵樹長出了一些果子,即某個子樹中的每個節點都會長...

BZOJ 3589 動態樹 樹鏈剖分 線段樹

題目傳送門 最近心真的有點浮躁啊 連題目都不想好好看了 於是就把 一條樹枝其實就是乙個從某個節點到根的路徑的一段 看成了 一條樹枝其實就是乙個從某個節點到根的路徑 wqnmlgb 操作1的k 5 那麼是不是會想到容斥?對兩條路徑求交?但是分析一下時間複雜度,o m log22n 2k 接近20億啊 ...

BZOJ3589 動態樹 樹鏈剖分 線段樹

別忘了這是一棵動態樹,每時每刻都是動態的.小明要求你在這棵樹上維護兩種事件 事件0 這棵樹長出了一些果子,即某個子樹中的每個節點都會長出k個果子.事件1 小明希望你求出幾條樹枝上的果子數.一條樹枝其實就是乙個從某個節點到根的路徑的一段.每次小明會選定一些樹枝,讓你求出在這些樹枝上的節點的果子數的和....