題面就不貼上了
/*把每個玩家的路徑拆成一條到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的連續正整數。...