按照常規思路,選乙個點x作為分治中心,拼接x出發到子樹各點的路徑。對於拼接時兩段介面處(即x連出的那條邊,若沒有,設為0號邊:顏色為0,長度為0,到達0號兒子)顏色的影響,可以記錄每段的路徑權值、邊數以及該段的介面,將所有的路徑以介面顏色為第一關鍵字,介面編號為第二關鍵字排序。顯然,對於同一介面的路徑必為連續的一段序列。這樣列舉每個路徑,找到之前出現的符合邊數和的要求的最大的路徑權值即可。用兩顆線段樹維護,一棵維護與本路徑不同顏色的,一顆維護與本路徑顏色相同但介面不同的(因為簡單路徑的拼接要滿足兩個端點不在同乙個子樹內)。
時間複雜度 o(nlognlogn)
常數巨大,需要吸氧和c++11
#include using namespace std;
const int n=2e5+10;
const int m=4e5+10;
const int inf=0x3f3f3f3f;
int n,m,l,r;
int c[n],head[n],to[m],clr[m],last[m];
int sum,top,rt,fiz[n],siz[n];
bool ban[n];
struct seg p[n];
struct rmq
void pushdown(int x)
void modify(int x,int l,int r,int p,int w)
int query(int x,int l,int r,int l,int r)
inline void modify(int p,int w)
inline int query(int l,int r)
#undef ls
#undef rs
} a,b;
void addedge(int x,int y,int c)
void getroot(int x,int pa)
fiz[x]=max(fiz[x],sum-siz[x]);
if(fiz[x]} int ans=-2e9;
void getdis(int x,int pa,int dis,int num,int pclr,int bel) ;
for(int i=head[x]; i; i=last[i])
}void calc(int x) ;
for(int i=head[x]; i; i=last[i])
sort(p+1,p+top+1,[=](seg x,seg y));
a.clear();
b.clear();
for(int l=1,r; l<=top; l=r+1)
b.clear();
if(l!=1) for(int i=l; i<=r; ++i)
ans=max(ans,p[i].dis+a.query(l-p[i].num,r-p[i].num));
for(int i=l; i<=r; ++i) a.modify(p[i].num,p[i].dis); }}
void solveat(int x)
}int main()
rt=0;
sum=n;
fiz[0]=2e9;
getroot(1,0);
solveat(rt);
printf("%d\n",ans);
return 0;
}
BJOI2017 樹的難題 點分治 線段樹
傳送門 傳送門 題意 給一棵樹,樹上有顏色,每種顏色有權值,定義一條路徑的權值為所有顏色相同段的權值之和,求長度在 l,r l,r l,r 中的路徑的最大權值。資料範圍 暴力過不了 顯然是個點分治 對於分治中心考慮過中心的路徑貢獻的答案 以下的 子樹 指根直接與分治中心相連的子樹 把分治中心作為根,...
BJOI2017 樹的難題 點分治,線段樹合併
lg傳送門 點分治 線段樹合併。我不會寫單調佇列,所以就寫了好寫的線段樹。考慮對於每乙個分治中心,把出邊按顏色排序,這樣就能把顏色相同的子樹放在一起處理。用一棵動態開點線段樹維護顏色不同的子樹的資訊,另一棵動態開點線段樹維護顏色相同的子樹的資訊,同時按照題目要求更新答案。當子樹顏色變化時,就把第二棵...
BJOI2017 魔法咒語
矩陣乘法 ac 自動機 是道很不錯的題了 首先是前六十分,就是乙個 ac 自動機上的套路 dp 設 dp i j 表示匹配出的長度為 i 在自動機上位置為 j 的方案數,轉移的話就列舉下乙個單詞選擇哪個放到自動機上一波匹配就好了 後面 40 分強行變成了另外一道題,l 變成了 1e8 一看就是矩乘的...