BZOJ2243 樹鏈剖分 線段樹)

2022-08-05 16:03:16 字數 2488 閱讀 8071

problem 染色(bzoj2243)

題目大意

給定一顆樹,每個節點上有一種顏色。

要求支援兩種操作:

操作1:將a->b上所有點染成一種顏色。

操作2:詢問a->b上的顏色段數量。

解題分析

樹鏈剖分+線段樹。

開一個記錄型別,記錄某一段區間的資訊。l 表示區間最左側的顏色 , r 表示區間最右側的顏色 , sum 表示區間中顏色段數量。

合併時判斷一下左區間的右端點和有區間的左端點的顏色是否一樣。

樹上合併時需要用兩個變數ans1,ans2來儲存。ans1表示x往上走時形成的鏈的資訊,ans2表示y往上走時形成鏈的資訊。

當x和y位於同一條重鏈上時,有三個區間需要合併在一起,注意判斷順序。

參考程式

1 #include 2 #include 3 #include 4 #include 5

using

namespace

std;67

#define v 100008

8#define e 200008

9#define lson l,m,rt<<1

10#define rson m+1,r,rt<<1|1

1112

intn,m,cnt;

13int

a[v],size[v],dep[v],fa[v],son[v],top[v],w[v],rk[v];

1415

struct

lineeg[e];

18int

sum,lt[v];

1920

struct

color

23};

24color merge(color a,color b)

33else

3439

return

c;40}41

42struct

segment_tree

48void pushdown(int

rt)57}58

void build(int l,int r,int

rt)64

int m=(l+r)/2;65

build(lson);

66build(rson);

67pushup(rt);68}

69void update(int l,int r,int val,int l,int r,int

rt)76

pushdown(rt);

77int m=(l+r)/2;78

if (l <=m) update(l,r,val,lson);

79if (m

80pushup(rt);81}

82 color query(int l,int r,int l,int r,int

rt)86

pushdown(rt);

87color res;

88int m=(l+r)/2;89

if (l <= m) res=merge(res,query(l,r,lson));

90if (m < r) res=merge(res,query(l,r,rson));

91return

res;92}

93}t;

9495

void adt(int u,int

v)98

void add(int u,int

v)101

102void dfs_1(int

u)112

}113

void dfs_2(int u,int

tp)121

}122

void change(int x,int y,int

val)

128if (dep[x]>dep[y]) swap(x,y);

129 t.update(w[x],w[y],val,1,n,1

);130

}131

void

pt(color a)

134void find(int x,int

y)141

else

142146

147}

148if (dep[x]

154else

155161 printf("

%d\n

",ans.sum );

162}

163164

intmain()

173 dfs_1(1

);174 dfs_2(1,1

);175 t.build(1,n,1

);176

while (m--)

184else

185;

189}

190 }

view code

BZOJ 2243 染色 樹鏈剖分

題意 給出一棵樹,每個頂點上有個顏色 c i 。 有兩種操作 分析 首先樹鏈剖分,下面考慮線段樹部分 我們維護一個區間的左端點的顏色和右斷點的顏色以及該區間的顏色段數,在加一個顏色覆蓋標記。 在pushup的時候,如果左區間右端點顏色和右區間左端點顏色相同,那麼這段顏色可以合併,合併區間的顏色段數為...