LuoGu P2664 樹上遊戲

2022-08-19 22:33:07 字數 2029 閱讀 1317

portal

這題真的好.

看到樹上路徑, 腦子裡就要點分治

這一題對於每個點都要計算一遍, 如果暴算實在不好算, 這樣我們就可以考慮算貢獻.

直接計算每種顏色的貢獻.

因為一條過重心的路徑中, 可能兩邊都會有相同顏色, 那麼我們就只考慮當前點到分治中心的鏈上.

然後把多算的這條鏈上的東西刪除就可以了.

copy from here

那麼我們就可以這樣做了:

1.對樹進行第一遍dfs,預處理size和上方性質中的貢獻。(開乙個color陣列即可記錄貢獻),同時記錄貢獻總和sum

2.列舉跟的所有子樹,先把子樹掃一遍清除其在color陣列中的所有貢獻。接著,對於該子樹中的每乙個點j:

設x=sigma color[j 到根上(不包括根)的所有顏色] 由於這些顏色已經出現過,我們不能在該子樹外計算其貢獻)

設num為j到根上(不包括根)的顏色數

設y為size[root]-size[該子樹](即所有其他子樹+根的點數)

則ans[j]+=sum-x+num*y;

3.別忘了計算單獨root的ans

ans[root]+=sum-color[根的顏色]+size[root]

4.清空貢獻陣列以及其他東西

#includeusing namespace std;

#define rep(i, a, b) for(int i = (a), i##_end_ = (b); i <= i##_end_; ++i)

#define drep(i, a, b) for(int i = (a), i##_end_ = (b); i >= i##_end_; --i)

#define clar(a, b) memset((a), (b), sizeof(a))

#define debug(...) fprintf(stderr, __va_args__)

typedef long long ll;

typedef long double ld;

int read()

void write(int x)

const int maxn = 100009;

struct edge g[maxn << 1];

int n, a[maxn], head[maxn], e;

void add(int u, int v) , head[u] = e;

}void init()

}ll ans[maxn], vis[maxn], tmp, heart;

int size[maxn];

void dfs(int u, int pa) }}

void centroid(int u, int pa, int field)

} if (bbs < tmp) tmp = bbs, heart = u;

}ll color[maxn], sum, cnt[maxn], size1[maxn];

void dfs_init(int u, int pa)

} if (cnt[a[u]] == 1)

--cnt[a[u]];

}void change(int u, int pa, int delta)

if (cnt[a[u]] == 1)

--cnt[a[u]];

}void count(int u, int pa, int x, int y, int num)

ans[u] += sum - x + num * y;

for (int i = head[u]; ~i; i = g[i].nxt)

--cnt[a[u]];

}void dfs_clear(int u, int pa)

}void calc(int u)

} dfs_clear(u, 0), sum = 0;

}void divconquer(int u)

}void solve()

int main()

Luogu P2664 樹上遊戲

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

P2664 樹上遊戲

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

P2664 樹上遊戲

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