天天愛跑步 noip2016day1t2

2021-08-14 11:24:33 字數 1446 閱讀 4169

2023年考到一片oier的題目。利用樹上的差分來解決這個問題

。先求出兩個節點的lca,然後分成向上跑和向下跑兩個鏈。

向上從起點跑到lca,這個過程累加,過了lca,對統計的貢獻就沒有了,減掉。因此就結點來說統計乙個節點有多少人,就觀察點i來說,如果觀察點的值是wi,需要統計觀察點下方deep[i]+wi深度有幾個節點。

向下從根節點跑到lca。從節點左側d=deep[st]-deep[lca]深度跑來,相當於從deep[lca]-d這個方向上跑來。因此需要重新記錄這個結束點對應的起點深度。對其lca來說也是一樣的,也要記錄這個起點深度。在en點和lca點之間的跑步是有效的。因此en以上統計,lca以上不再統計,減去!

以上兩個在樹上的統計用dfs完成,統計每個節點 所有的孩子中,距離其深度為wi的人有幾個。

在這個過程中,如果恰好節點i的值wi=deep[st]-deep[i],那麼這個點在上行時候被統計一次,下行時候也被統計一次,先減去一次。再在其父節點減一次,這項就差分啦。

所以,題目的整體步驟應該先求深度、lca(倍增或tarjan),再根據上面的方法處理。

小細節:因為起點根據lca翻轉後的深度可能小於0,因此規定根節點的深度為3e5.

#include#include#include#includeconst int maxn=300009;

using namespace std;

struct node

}edge[2*maxn],ques[2*maxn];

struct node2

};int n,m,s,anslca[maxn],flca[maxn],st[maxn],ed[maxn],dep[maxn],fa[maxn],cnt=0,w[maxn];

int head[maxn],qhead[maxn];

bool vis[maxn];

int add(node e,int hd,int u,int v,int w);

hd[u]=cnt;

e[++cnt]=;

hd[v]=cnt;

}int find(int x)

void tarlca(int u)

}for(int i=qhead[u];i>0;i=ques[i].next)

}}vectorcup[maxn],cdown[maxn];

int aup[2*maxn],adown[2*maxn],ans[maxn];

void dfs(int u)

} ans[u]+=aup[dep[u]+w[u]];

ans[u]+=adown[dep[u]-w[u]];

}int main(){

memset(head,0,sizeof(head));

memset(qhead,0,sizeof(qhead));

int a,b;

scanf("%d%d",&n,&m);

for(int i=1;i

天天愛跑步NOIP

首先,我們考慮對於一條路徑 從x y,可以把它拆分成兩部分,圖中用虛線分開,然後這條路徑就變成了x lca,son lca y 先來考慮從x向上走到lca的路徑,對於這條路上的節點i,玩家能對節點i產生貢獻的前提是deep x w i deep i 移項可得deep x w i deep i 也就是...

NOIP2016 天天愛跑步

時間限制 2 s 記憶體限制 512 mb 題目描述 小c同學認為跑步非常有趣,於是決定製作一款叫做 天天愛跑步 的遊戲。天天愛跑步 是乙個養成類遊戲,需要玩家每天按時上線,完成打卡任務。這個遊戲的地圖可以看作一棵包含n個結點和n 1條邊的樹,每條邊連線兩個結點,且任意兩個結點存在一條路徑互相可達。...

NOIP2016天天愛跑步

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