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 的路徑詢問,通過有效的 劃分,使之能在穩定的時間內通過儲存資訊 獲取資訊的經典方式來求 出答案。由此看出點分治的關鍵在於儲存資訊與獲取資訊的方式。點分治的模板套上之後我們只需要考慮的是子樹與子...