洛谷P1600 天天愛跑步 差分 LCA 桶

2022-04-30 01:12:20 字數 2034 閱讀 7250

題目鏈結

一步一步的來考慮

\(25 \%\):直接\(o(nm)\)的暴力

鏈的情況:維護兩個差分陣列,分別表示從左向右和從右向左的貢獻,

\(s_i = 1\):統計每個點的子樹內有多少起點即可

\(t_i = 1\):同樣還是差分的思想,由於每個點 能對其產生的點的深度是相同的(假設為\(x\)),那麼訪問該點時記錄下\(dep[x]\)的數量,將結束時\(dep[x]\)的數量與其做差即可

滿分做法和上面類似,我們考慮把每個點的貢獻都轉換到子樹內統計

對於每次詢問,拆為\(s->lca, lca -> t\)兩種(從下到上 / 從上到下)

從上往下需要滿足的條件:\(dep[i] - w[i] = dep[t] - len\)

從下往上需要滿足的條件:\(dep[i] + w[i] = dep[s]\)

#include#define pair pair#define mp make_pair

#define fi first

#define se second

using namespace std;

const int maxn = 1e6 + 10, mod = 1e9 + 7, b = 20;

inline int read()

while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();

return x * f;

}int n, m, ans[maxn], dep[maxn], top[maxn], son[maxn], siz[maxn], fa[maxn], s[maxn],

t[maxn], w[maxn], tmp[maxn], num2[maxn], sum1[maxn], sum2[maxn], lca[maxn];

int *num1;//上 -> 下

vectorup[maxn], da[maxn], dc[maxn];

vectorv[maxn];

void dfs(int x, int _fa)

}void dfs2(int x, int topf)

int lca(int x, int y)

return dep[x] < dep[y] ? x : y;

}void deal(int s, int t, int id)

void find(int x)

num2[dep[x]] += sum2[x];

for(int i = 0; i < da[x].size(); i++) num1[da[x][i]]++;

ans[x] += num2[dep[x] + w[x]] - t2 + num1[dep[x] - w[x]] - t1;

for(int i = 0; i < up[x].size(); i++) num2[dep[up[x][i]]]--;

for(int i = 0; i < dc[x].size(); i++) num1[dc[x][i]]--;

}int main()

dep[0] = -1; dfs(1, 0); dfs2(1, 1);

//for(int i = 1; i <= n; i++, puts("")) for(int j = 1; j <= n; j++) printf("%d %d %d\n", i, j, lca(i, j));

for(int i = 1; i <= n; i++) w[i] = read();

for(int i = 1; i <= m; i++) s[i] = read(), t[i] = read(), deal(s[i], t[i], i);

find(1);

for(int i = 1; i <= m; i++) if(dep[s[i]] - dep[lca[i]] == w[lca[i]]) ans[lca[i]]--;

for(int i = 1; i <= n; i++) printf("%d ", ans[i]);

return 0;

}

洛谷 P1600 天天愛跑步

題面就不貼上了 把每個玩家的路徑拆成一條到lca的路徑和從lca到終點的路徑 然後,使用樹上差分統計答案即可 那麼,樹上差分是什麼?差分的具體思想是,當某區間內某元素對答案有貢獻,就在區間起點打乙個 1 標記代表多出了乙個對答案有貢獻的元素,在終點打乙個 1標記代表乙個對答案有貢獻的元素在該位置 結...

洛谷P1600 天天愛跑步

樹上的題有點意思啊 這題我最開始的想法是 固定乙個觀測點i,能觀測到的一定是起點距離 i 為 w i 的點的子集合。問題是這個集合只有一部分的點會經過 i 點,就很煩。於是得換個思路,不放固定乙個跑步的人 x 觀察他對哪些觀察者 i 產生了貢獻。於是我們得到了公式,對於上公升階段的點來說,不妨設 s...

洛谷 P1600 天天愛跑步(LCA 亂搞)

傳送門 我們把每一條路徑拆成 u lca 和 lca v 的路徑 先考慮 u lca 如果這條路徑會對路徑上的某乙個點產生貢獻,那麼滿足 dep u dep x w x dep u dep x w x 注意到 dep x w x 是乙個定值,所以我們只要去找它的子樹裡有多少個點的 dep 等於 de...