BJOI2017 樹的難題 點分治 線段樹

2021-09-25 20:56:15 字數 3222 閱讀 2729

傳送門

傳送門

題意:給一棵樹,樹上有顏色,每種顏色有權值,定義一條路徑的權值為所有顏色相同段的權值之和,求長度在[l,

r]

[l,r]

[l,r

]中的路徑的最大權值。

資料範圍:暴力過不了

顯然是個點分治

對於分治中心考慮過中心的路徑貢獻的答案

(以下的「子樹」指根直接與分治中心相連的子樹)

把分治中心作為根,定義一棵子樹的顏色為與根(即分治中心)相連的邊的顏色

顯然可以算出兩邊的貢獻,如果兩邊顏色一樣,再減掉這個權值

有個單調佇列的神仙做法,看不懂

所以自己yyyy

yy了線段樹做法(題解也有)

把所有子樹按顏色排序,把相同顏色放一起

維護兩棵線段樹,表示長度為x

xx的路徑的最大權值,一棵維護相同顏色,一棵維護不同顏色

遍歷所有子樹的所有節點,設當前節點的深度為dis

disdi

s,區間查詢兩棵線段樹中[l−

dis,

r−di

s]

[l-dis,r-dis]

[l−dis

,r−d

is]的答案。

遍歷完一棵子樹後,將它們加入同色線段樹。

當進入不同顏色時,把前乙個顏色的點插入異色線段樹,並給同色線段樹打清除標記

複雜度大概o(n

logn

2)

o(nlog_n^2)

o(nlog

n2​)

#include

#include

#include

#include

#include

#define maxn 200005

#define maxm 400005

#define re register

#define inf 0x3f3f3f3f

using

namespace std;

class

fast_input

public

:template

<

class

t>

void

operator()

(t &x)

void

operator()

(char

&c,char l =

'a',

char r =

'z')

}input;

struct edgee[maxm]

;int head[maxn]

,nxt[maxm]

,cnt;

void

addnode

(int u,

int v,

int w)

; nxt[cnt]

=head[u]

; head[u]

=cnt;

}int cost[maxn]

,n,m,l,r;

bool cut[maxn]

;int siz[maxn]

,sum[maxn]

,maxp[maxn]

,root;

void

findroot

(int u,

int f,

int sum)

if(sum-siz[u]

>maxp[u]

) maxp[u]

=sum-siz[u];if

(maxp[u]

) root=u;

}struct sgt

inline

void

pushdown

(int p)

void

build

(int p,

int l,

int r)

void

modify

(int p,

int l,

int r,

int k,

int v)

intquery

(int p,

int l,

int r,

int ql,

int qr)

inline

void

clear()

}sam,dif;

int ans=

-inf,maxlen;

int nod[maxn]

,col[maxn]

;inline

bool

cmp(

const

int& a,

const

int& b)

int tot;

int len[maxn]

,val[maxn]

,num,_len[maxn]

,_val[maxn]

,_num;

intdfs

(int u,

int f,

int l,

int v,

int las_col)

void

calc()

sum[nod[i]]=

dfs(nod[i],0

,1,cost[col[nod[i]]]

,col[nod[i]])

;for

(re int u=

1;u<=num;u++

)for

(re int u=

1;u<=num;u++

) sam.

modify(1

,1,n,len[u]

,val[u]);

num=0;

} sam.

clear()

,dif.

clear()

; tot=num=_num=0;

}void

solve()

}int

main()

sam.

build(1

,1,n),dif.

build(1

,1,n);

maxp[root=0]

=inf;

findroot(1

,0,n);

solve()

;printf

("%d\n"

,ans)

;return0;

}

BJOI2017 樹的難題 點分治,線段樹合併

lg傳送門 點分治 線段樹合併。我不會寫單調佇列,所以就寫了好寫的線段樹。考慮對於每乙個分治中心,把出邊按顏色排序,這樣就能把顏色相同的子樹放在一起處理。用一棵動態開點線段樹維護顏色不同的子樹的資訊,另一棵動態開點線段樹維護顏色相同的子樹的資訊,同時按照題目要求更新答案。當子樹顏色變化時,就把第二棵...

BJOI2017 樹的難題

按照常規思路,選乙個點x作為分治中心,拼接x出發到子樹各點的路徑。對於拼接時兩段介面處 即x連出的那條邊,若沒有,設為0號邊 顏色為0,長度為0,到達0號兒子 顏色的影響,可以記錄每段的路徑權值 邊數以及該段的介面,將所有的路徑以介面顏色為第一關鍵字,介面編號為第二關鍵字排序。顯然,對於同一介面的路...

樹的點分治

codeforces 150e 通過點分治以及合併子樹檢查二分的答案 用深度從小到大的方式可以剪枝,達到nlog 2 n 的複雜度 不離散化常數巨大,離散化常數依然巨大 include include include include include define maxn 100005 define...