刷題 洛谷 P2664 樹上遊戲

2022-05-26 14:30:10 字數 2693 閱讀 2164

lrb有一棵樹,樹的每個節點有個顏色。給乙個長度為n的顏色序列,定義s(i,j) 為i 到j 的顏色數量。以及

\[sum_i=\sum_^ns(i,j)

\]現在他想讓你求出所有的sum[i]

輸入格式:

第一行為乙個整數n,表示樹節點的數量

第二行為n個整數,分別表示n個節點的顏色c[1],c[2]……c[n]

接下來n-1行,每行為兩個整數x,y,表示x和y之間有一條邊

輸出格式:

輸出n行,第i行為sum[i]

輸入樣例#1:

51 2 3 2 3

1 22 3

2 41 5

輸出樣例#1:109

11912

sum[1]=s(1,1)+s(1,2)+s(1,3)+s(1,4)+s(1,5)=1+2+3+2+2=10

sum[2]=s(2,1)+s(2,2)+s(2,3)+s(2,4)+s(2,5)=2+1+2+1+3=9

sum[3]=s(3,1)+s(3,2)+s(3,3)+s(3,4)+s(3,5)=3+2+1+2+3=11

sum[4]=s(4,1)+s(4,2)+s(4,3)+s(4,4)+s(4,5)=2+1+2+1+3=9

sum[5]=s(5,1)+s(5,2)+s(5,3)+s(5,4)+s(5,5)=2+3+3+3+1=12

對於40%的資料,n<=2000

對於100%的資料,1<=n,c[i]<=10^5

用的點分治做

這道題我看題解都看了很久啊

nyg和zlt用虛樹做的,於是我就只能默默地乙個人看點分的做法

首先看找到分治中心後看怎麼算根的答案,因為點對中乙個點一定是根,所以就是求每個點到根的路徑上有多少個不同的顏色;然後把計算答案的方法變一下,把統計點的貢獻變成統計顏色的貢獻

那麼如果乙個點的顏色是在這個點到根的路徑上第一次出現,那麼這個顏色就可以對答案貢獻當前點的size大小貢獻(因為點對中另乙個點只要是這個點的子樹中的點,那麼由於會經過當前點,而這個點的顏色又是第一次出現,那麼肯定每個點對的貢獻都會加1,那麼對於這個顏色來說,就會加size貢獻)

\(colvl[x]\) 代表顏色 \(x\) 的貢獻,\(allval\) 就是統計 \(colvl\) 的和

那麼根的答案就直接為 \(allval\)

由於分治算的答案都是必經過根的,所以我們接著會發現開始我們統計的 \(colvl[i]\) 同樣使用於除根外的其它點 \(x\) ,但要保證 \(x\) 到根的路徑上不能出現 \(i\) 的顏色,並且同一子樹中的點不能對其顏色有貢獻,這不就是點分不去重的搞法嗎

然後就好了

每次找完root後,dfs一遍算 \(colvl\) 和 \(allval\),然後把根的貢獻搞出來

然後列舉每乙個子樹,dfs一遍把當前的子樹的貢獻去掉,再dfs一遍把去掉貢獻的子樹的答案算一下,最後dfs一遍把去掉的貢獻加回來

點分治就做完了

#include#define ui unsigned int

#define ll long long

#define db double

#define ld long double

#define ull unsigned long long

const int maxn=100000+10,inf=0x3f3f3f3f;

int n,col[maxn],e,to[maxn<<1],nex[maxn<<1],beg[maxn],msonsize[maxn],size[maxn],root,colnt[maxn],finish[maxn];

ll allval,colvl[maxn],ans[maxn];

templateinline void read(t &x)

templateinline void write(t x,char ch='\0')

templateinline void chkmin(t &x,t y)

templateinline t min(t x,t y)

inline void insert(int x,int y)

inline void getroot(int x,int f,int total)

chkmax(msonsize[x],total-size[x]);

if(msonsize[x]}inline void dfs1(int x,int f)

colnt[col[x]]--;

}inline void dfs2(int x,int f,int k)

colnt[col[x]]--;

}inline void dfs3(int x,int f,int other,int colnm)

inline void clear(int x,int f)

inline void calc(int x)

clear(x,0);

}inline void solve(int x)

}int main()

msonsize[0]=inf;

getroot(1,0,n);

solve(root);

for(register int i=1;i<=n;++i)write(ans[i],'\n');

return 0;

}

洛谷 P2664 樹上遊戲

lrb有一棵樹,樹的每個節點有個顏色。給乙個長度為n的顏色序列,定義 s i,j 為 i 到 j 的顏色數量。以及 sum i sum s i,j 現在他想讓你求出所有的 sum i 這題真是難,點分治神題 我們考慮乙個性質,對於乙個點 i 如果它的顏色在到根的路徑中是第一次出現,那麼對於和 i 不...

P2664 樹上遊戲

分析 點分治。首先關於答案的統計轉化成計算每個顏色的貢獻。1 計算從根出發的路徑的答案 如果某乙個顏色是從根到這個點的鏈上的第一次出現的,那麼這個顏色會對根產生siz x 個貢獻。根連向它子樹的任意乙個點的路徑都包含這個顏色 2 計算子樹內每個點過根的路徑答案 記錄乙個陣列sum i 表示從根出發包...

P2664 樹上遊戲

題面 作為一道經典的點分治題目,此題能很好的考察對點分治的運用。個人認為點分治的本質在於 對於樹上近乎n2 的路徑詢問,通過有效的 劃分,使之能在穩定的時間內通過儲存資訊 獲取資訊的經典方式來求 出答案。由此看出點分治的關鍵在於儲存資訊與獲取資訊的方式。點分治的模板套上之後我們只需要考慮的是子樹與子...