bzoj2243 樹鏈剖分 染色

2021-08-14 01:38:08 字數 3084 閱讀 3067

description

給定一棵有n個節點的無根樹和m個操作,操作有2類: 1、將節點a到節點b路徑上所有點都染成顏色c;

2、詢問節點a到節點b路徑上的顏色段數量(連續相同顏色被認為是同一段), 如「112221」由3段組成:「11」、「222」和「1」。

請你寫乙個程式依次完成這m個操作。

input

第一行包含2個整數n和m,分別表示節點數和運算元; 第二行包含n個正整數表示n個節點的初始顏色 下面

行每行包含兩個整數x和y,表示x和y之間有一條無向邊。 下面 行每行描述乙個操作: 「c a b

c」表示這是乙個染色操作,把節點a到節點b路徑上所有點(包括a和b)都染成顏色c; 「q a

b」表示這是乙個詢問操作,詢問節點a到節點b(包括a和b)路徑上的顏色段數量。

output

對於每個詢問操作,輸出一行答案。

sample input

6 5

2 2 1 2 1 1

1 2

1 3

2 4

2 5

2 6

q 3 5

c 2 1 1

q 3 5

c 5 1 2

q 3 5

sample output

3 1 2

hint

數n<=10^5,運算元m<=10^5,所有的顏色c為整數且在[0, 10^9]之間。

題解

這個一眼就能看出來樹剖吧。。

樹剖的線段樹的話維護一下這一段最左邊的顏色,最右邊的顏色,以及本身的顏色(不是純色的話就為-1),打個lazy搞一下。。

修改我就不廢話了大家都會吧。。

查詢時x和y往上跳的時候分別維護兩個值lasx和lasy,表示x,y當前查詢到的最後一段上最上面那段的顏色。線段樹問的時候維護兩個值fir和tmp,表示當前查詢這一段最下面的顏色和最上面的顏色。出來之後看一看fir和跳的這個las是不是相等,相等的話答案就要-1。之後las繼承為tmp

如果你分不清我上面說的las的話請你看一看樹剖跳輕重鏈的過程。那裡會把lasx和lasy交換一下的

線段樹查詢的時候有乙個小小的坑點。。上面說要維護一下這個段最左邊和最右邊的顏色,就是因為怕分開查詢的時候中間連線的地方其實是一段,然後那裡也是需要判一下的。。

實在聽不下去我口胡的可以看一看**。。我覺得可看性還是挺強的

#include

#include

#include

#include

#include

using namespace std;

struct node

a[211000];int len,last[111000];

void ins(int

x,int

y)int fa[111000],dep[111000],tot[111000],son[111000],n,m;

void pre_tree_node(int

x) }

}int ys[111000],top[111000],z;

void pre_tree_edge(int

x,int tp)

struct trnode

tr[410000];int trlen;

void bt(int l,int r)

}void upd(int

x)int lasx,lasy,fir,tmp,col[111000];

void change(int now,int l,int r,int c)

intlc=tr[now].lc,rc=tr[now].rc;

int mid=(tr[now].l+tr[now].r)/2;

if(tr[now].lazy)upd(now);

if(r<=mid)change(lc,l,r,c);

else

if(mid+1

<=l)change(rc,l,r,c);

else change(lc,l,mid,c),change(rc,mid+1,r,c);

if(tr[lc].c==tr[rc].c)tr[now].c=tr[lc].c;

else

tr[now].c=-1;

tr[now].lef=tr[lc].lef;

tr[now].rig=tr[rc].rig;

}int findsum(int now,int l,int r,int lef,int rig)

intlc=tr[now].lc,rc=tr[now].rc;

int mid=(tr[now].l+tr[now].r)/2;

if(tr[now].lazy)upd(now);

if(r<=mid)return findsum(lc,l,r,lef,rig);

else

if(mid+1

<=l)return findsum(rc,l,r,lef,rig);

else

}void chmul(int

x,int

y,int c)

if(x==y)

else

}int sol(int

x,int

y) if(x==y)

else

}int main()

fa[1]=0;dep[1]=0;pre_tree_node(1);

z=0;pre_tree_edge(1,1);

trlen=0;bt(1,z);

for(int i=1;i<=n;i++)change(1,ys[i],ys[i],col[i]);

while(m--)

else

printf("%d\n",sol(x,y));

}return

0;}

bzoj 2243 染色 樹鏈剖分

首先這是個挺裸的題,由於太久沒寫剖分導致調了好久,前天調了一下午,一直查不到錯 昨晚在看春晚的時候突然靈機一動,發現合併的時候出了問題,開電腦把它a掉了 感覺自己也蠻拼的給定 一棵有n 個節點的 無根樹和 m個操作 操作有 2類 1 將節點a 到節點b 路徑上所 有點都染 成顏色c 2 詢問節點a ...

bzoj 2243 樹鏈剖分 染色

time limit 20 sec memory limit 512 mb submit 3205 solved 1238 submit status discuss 給定一棵有n個節點的無根樹和m個操作,操作有2類 1 將節點a到節點b路徑上所有點都染成顏色c 2 詢問節點a到節點b路徑上的顏色段...

BZOJ 2243 染色 樹鏈剖分

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