\(\text\)有一棵樹,樹的每個節點有個顏色。給乙個長度為\(n\)的顏色序列,定義\(s(i,j)\) 為 \(i\) 到 \(j\) 的顏色數量。以及\(sum_i=\sum\limits_^ns(i,j)\)
現在他想讓你求出所有的\(sum_i\)
第一行為乙個整數\(n\),表示樹節點的數量
第二行為\(n\)個整數,分別表示\(n\)個節點的顏色\(c[1],c[2],\dots,c[n]\)
接下來\(n-1\)行,每行為兩個整數\(x,y\),表示\(x\)和\(y\)之間有一條邊
輸出\(n\)行,第\(i\)行為\(sum[i]\)
對於\(40\%\)的資料,\(n\le 2000\)
對於\(100\%\)的資料,\(1\le n,c[i]\le10^5\)
本辣雞深深的認識到了自己的澱粉質寫法有多麼的詭異..
這個題在澱粉質上的思路還是比較簡單的,就是寫起來很煩人。
我的做法大致是
每次出去遍歷子樹時維護乙個當前鏈顏色集合和乙個過點分治根的每個顏色所屬鏈的個數。然後每個點根據個數加一些本身顏色的貢獻就可以了。注意要從左從右各做一遍。
說起來比較簡單,但實際上還是要想一想的。
然後我拿\(map\)樂呵呵的維護顏色集合然後成功t飛
發現拿陣列就可以了,但是最後要dfs去清空陣列。
code:
#include #include #include #include #define ll long long
const int n=1e5+10;
int read()
return x;
}std::vector edge[n];
ll sum[n];
const int inf=0x3f3f3f3f;
int n,c[n],siz[n],del[n],mi,rt,lassiz,typ,sumnow;
void getroot(int now,int fa,int s)
mx=mx>s-siz[now]?mx:s-siz[now];
if(mi>mx) rt=now,mi=mx;
}int nowcolor[n];//存到根的顏色集合
ll lascolor[n],tlascolor[n];//存外面的鏈每種顏色在多少條鏈出現過
void dfs(int now,int fa,int totcolor,ll outsum)
sum[now]+=outsum;
sum[now]=sum[now]-totcolor*typ;//減去統計自己與根的答案
sumnow+=totcolor;
for(int i=0;i2018.12.4
洛谷 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 的路徑詢問,通過有效的 劃分,使之能在穩定的時間內通過儲存資訊 獲取資訊的經典方式來求 出答案。由此看出點分治的關鍵在於儲存資訊與獲取資訊的方式。點分治的模板套上之後我們只需要考慮的是子樹與子...