天天愛跑步有點毒瘤的題目 我們觀察一下性質 在路徑 u,v 上 如果這個路徑 對某個點j 有貢獻j肯定得在路徑 u,v上 也就是說 如果當前遍歷的點在 lca(u,v)上方的話 那麼 u,v路徑是肯定沒有貢獻的 因此到達lca時我們要把貢獻去掉
在說怎麼算貢獻
設u為起始點 v為終止點
如果u對於j有貢獻 有
如果v對於j有貢獻 則設u,v路徑的時間為 t 有
又化簡可得
然後需要注意的幾點:
1.當我們遍歷的點為lca(u,v)的時候 顯然上面兩個情況都會有貢獻 所以我們要在lca處先去掉一種情況 再在 fa[lca]處在去掉另一種 類似差分的思想
2.當w[j]=0時要特判一下
#includeusing namespace std;
const int n = 3e5+100;
const int m = n*50;
int n,m;
int sum[m],ls[m],rs[m],rt[n],pot[m],tot,ct,w[n],dep[n],lg[n],fa[n][30];
int h[n],nex[n<<1],to[n<<1],cur,ans[n];
void add_edge(int x,int y)
inline int in()
inline int newnode()
inline void del(int x)
inline void pushup(int o)
void upd(int &o,int l,int r,int pos,int v)
int mid = l+r>>1;
if(pos<=mid) upd(ls[o],l,mid,pos,v);
else upd(rs[o],mid+1,r,pos,v);
pushup(o);
}int merge(int x,int y)
int query(int o,int l,int r,int pos)
void dfs1(int u,int f)
}int lca(int x,int y)
void dfs2(int u,int f)
if(w[u]&&n+dep[u]+w[u]<=2*n)
ans[u]+=query(rt[u],1,n<<1,n+dep[u]+w[u]);
ans[u]+=query(rt[u],1,n<<1,n+dep[u]-w[u]);
}int main()
for(int i = 1; i <= n; i++)
dfs1(1,0);
for(int i = 1; i <= m; i++)
dfs2(1,0);
for(int i = 1; i <= n; i++) printf("%d%c",ans[i],i==n?'\n':' ');
return 0;
}
洛谷P1600 天天愛跑步(線段樹合併)
小c同學認為跑步非常有趣,於是決定製作一款叫做 天天愛跑步 的遊戲。天天愛跑步 是乙個養成類遊戲,需要玩家每天按時上線,完成打卡任務。這個遊戲的地圖可以看作一一棵包含 nn個結點和 n 1n 1條邊的樹,每條邊連線兩個結點,且任意兩個結點存在一條路徑互相可達。樹上結點編號為從11到nn的連續正整數。...
洛谷 P1600 天天愛跑步
題面就不貼上了 把每個玩家的路徑拆成一條到lca的路徑和從lca到終點的路徑 然後,使用樹上差分統計答案即可 那麼,樹上差分是什麼?差分的具體思想是,當某區間內某元素對答案有貢獻,就在區間起點打乙個 1 標記代表多出了乙個對答案有貢獻的元素,在終點打乙個 1標記代表乙個對答案有貢獻的元素在該位置 結...
P1600 天天愛跑步 解題報告
用的是一種很容易理解但寫起來卻有點小煩的差分。演算法模型構建 本題實際上求的是兩種情況 1.在i節點下方的wi層有多少個 起點,2.在i節點下方的有多少個滿足一定條件的終點。情況1 也就是在末節點的再上乙個節點打上乙個del標記。而我們的答案就是此節點的子樹的起點集群中 dep j dep i w ...