洛谷 P1600 天天愛跑步

2021-08-08 01:21:24 字數 1811 閱讀 9337

題面就不貼上了

/*把每個玩家的路徑拆成一條到lca的路徑和從lca到終點的路徑~ 然後,使用樹上差分統計答案即可~ 

那麼,樹上差分是什麼? 差分的具體思想是,當某區間內某元素對答案有貢獻,就在區間起點打乙個+1

標記代表多出了乙個對答案有貢獻的元素,在終點打乙個-1標記代表乙個對答案有貢獻的元素在該位置

結束了它的使命。 於是,統計答案就變成了維護掃到當前位置為止的標記個數,直接累加就是答案~ 首先

對從下到上的路徑觀察~ 然後就會發現:所有對某點上的觀察員i有貢獻的點只可能是以i點往下w[i]層深

度的任一後代為起點的玩家~ 然後我們就可以維護乙個標記陣列,每個位置分別表示當前共訪問了多少個深

度為當前位置下標的點。 直接dfs,先對目標深度,也就是對當前觀察員i有貢獻的深度為dep[i]+w[i]的

標記,記錄其當前的值。 然後遞迴搜尋所有子樹,每搜到乙個點便把以當前點為起點的所有路徑加入當前點深

度的標記中,代表這些點開始產生貢獻,並把以當前點為lca的所有路徑從從該路徑起點所在深度中減去,代

表這些點停止產生貢獻。 當回溯到當前點,統計搜尋完所有子樹後dep[i]+w[i]處標記的新值,並減去記

錄下的舊的值,作為當前節點的答案~ 這樣搜一遍,正向的便被統計完了~ 從lca到終點的方法同理,只是

在dep[i]-w[i]時可能有負數出現,加上30000的偏移量即可~ */

#include

#include

#include

#include

#include

#include

using

namespace

std;

const

int maxn = 302333;

#define pb push_back

struct playera[maxn];

int to[maxn<<1],nxt[maxn<<1],head[maxn<<1],n,m,w[maxn],deep,tot;

vector

upper[maxn],down1[maxn],down2[maxn];

inline

void read(int &x)

while(c>='0'&&c<='9') x*=f;

}inline

void add_(int u,int v)

inline

void add_edge(int u,int v)

int top[maxn],dep[maxn],siz[maxn],son[maxn],fa[maxn];

int pos[maxn],ans[maxn],delta[maxn<<1];

void dfs1(int u,int father,int deepth)

}void dfs2(int u,int top)

}inline

int get_lca(int u,int v)

void dfs3(int u)

dfs3(1);

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

memset(delta,0,sizeof delta );

dfs4(1);

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

if(dep[a[i].s]==dep[a[i].lca]+w[a[i].lca])

--ans[a[i].lca];

printf("%d",ans[1]);

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

return

0;}

洛谷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...

洛谷P1600 天天愛跑步(線段樹合併)

小c同學認為跑步非常有趣,於是決定製作一款叫做 天天愛跑步 的遊戲。天天愛跑步 是乙個養成類遊戲,需要玩家每天按時上線,完成打卡任務。這個遊戲的地圖可以看作一一棵包含 nn個結點和 n 1n 1條邊的樹,每條邊連線兩個結點,且任意兩個結點存在一條路徑互相可達。樹上結點編號為從11到nn的連續正整數。...