洛谷 P2664 樹上遊戲

2022-06-19 18:45:08 字數 1812 閱讀 2078

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

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

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

這題真是難,點分治神題

我們考慮乙個性質,對於乙個點\(i\),如果它的顏色在到根的路徑中是第一次出現,那麼對於和\(i\)不在乙個子樹的點\(j\),對\(j\)都有\(i\)的子樹大小\(size_i\)的貢獻

然後有了這個性質,就好做了

找完重心後預處理出來實際的\(size\),用\(sum\)來記錄所有點的貢獻,\(s\)是這個顏色的貢獻

而我們不是用點去更新答案,是用顏色來更新答案,所以要枚舉子樹,去掉這個子樹的貢獻來統計答案

於是再有\(x\)表示除了這個子樹的點數和,\(co\)表示這個點到根的顏色數

然後記錄下這個點到根的所有顏色的\(s\)的和,\(s\)是要被減去的

那麼\(ans+=sum-s+co\times x\),然後單獨更新一下根就是\(ans+=sum-s_}+size_\)

code

#include #include #include #include const int n = 1e5;

using namespace std;

int n,c[n + 5],size[n + 5],maxp[n + 5],rt,su,vis[n + 5],cnt[n + 5];

long long sum,s[n + 5],ros,x,ans[n + 5];

vector d[n + 5];

void get_rt(int u,int fa)

maxp[u] = max(maxp[u],su - size[u]);

if (maxp[u] < maxp[rt])

rt = u;

}void get_size(int u,int fa)

}void dfs(int u,int fa,int w)

if (!cnt[c[rt]])

ros += w;

vector ::iterator it;

for (it = d[u].begin();it != d[u].end();it++)

cnt[c[u]]--;

}void upd(int u,int fa,int co,int su)

ans[u] += sum - su + co * x;

if (!cnt[c[rt]])

ans[u] += ros;

vector ::iterator it;

for (it = d[u].begin();it != d[u].end();it++)

cnt[c[u]]--;

}void calc(int u)

for (it = d[u].begin();it != d[u].end();it++)

ans[u] += sum - s[c[u]] + size[u];

for (it = d[u].begin();it != d[u].end();it++)

}void solve(int u)

}int main()

su = n;

maxp[0] = n;

get_rt(1,0);

get_size(rt,0);

solve(rt);

for (int i = 1;i <= n;i++)

printf("%lld\n",ans[i]);

return 0;

}

P2664 樹上遊戲

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

P2664 樹上遊戲

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

洛谷 P2664 樹上遊戲 解題報告

text 有一棵樹,樹的每個節點有個顏色。給乙個長度為 n 的顏色序列,定義 s i,j 為 i 到 j 的顏色數量。以及 sum i sum limits ns i,j 現在他想讓你求出所有的 sum i 第一行為乙個整數 n 表示樹節點的數量 第二行為 n 個整數,分別表示 n 個節點的顏色 c...