P1600 天天愛跑步 線段樹合併 lca

2021-10-07 22:10:11 字數 1516 閱讀 4562

天天愛跑步

有點毒瘤的題目  我們觀察一下性質  在路徑 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 ...