洛谷P1600 天天愛跑步

2021-10-01 01:34:31 字數 1970 閱讀 2087

樹上的題有點意思啊

這題我最開始的想法是 固定乙個觀測點i,能觀測到的一定是起點距離 i 為 w[ i ] 的點的子集合。問題是這個集合只有一部分的點會經過 i 點,就很煩。。。

於是得換個思路,不放固定乙個跑步的人 x 觀察他對哪些觀察者 i 產生了貢獻。

於是我們得到了公式,

對於上公升階段的點來說,不妨設 s 為起點  

d[x]+w[x] = d[s]( d為表示深度的陣列 )
對於下降階段的點來說,不妨設 t 為終點

dis[ s,t ] - d[t] = w[i] - deep[i]

這樣,我們就把問題準換成了查詢每個點的周圍滿足上述公式的點有多少個(注意,s和t 的lca處有可能會出現重複計算)

另外,上述表示式的值可能為負,所以用桶記錄的時候要加上乙個很大的值使其非負。

我們可以發現,對於每乙個觀察者 i 來說,經過他的路徑的起點和終點 至少有一端 在 以他為根的子樹中。於是我們將問題轉化成 查詢 在以 i 為根的子樹中滿足上述公式 且路徑經過i點 的點有多少個。

那麼我們重點解決的問題就是如何判斷路徑是否經過某個點。方法就是利用差分。對於每條路徑,我們在起點和終點的lca處記錄一下 起點和終點在這裡的貢獻,當從這個點回溯的時候,要把這個貢獻從桶中去掉。

剩下最後乙個問題就是這樣做的話,計算 i 點時桶的內容會包含 其他子樹的貢獻。方式就是進入 i 點的時候我們先記錄一下當時的貢獻,從 i 點回溯的時候我們再記錄一下此時桶中的內容,後者減去前者就是 以 i 為根節點的子樹的貢獻。 

#include #include#include using namespace std;

typedef long long ll;

typedef int lint;

typedef pairpii;

const lint maxn = 300000;

const lint maxm = 600000;

lint ver[maxm],ne[maxm],he[maxn],tot;

void init()

void add( lint x,lint y )

queueque;

lint d[maxn],f[maxn][21];

void build()

if( x == y ) return x;

for( lint i = 20;i >= 0;i-- )

return f[x][0];

}lint w[maxn],ans[maxn];

vectoriss[maxn];

vectorist[maxn];

lint tongs[5*maxn],tongt[5*maxn];

vectorves[maxn],vet[maxn];

lint buckets[maxn],buckett[maxn];

void dfs( lint x,lint f )

for( lint i = 0;i < iss[x].size();i++ )

for( lint i = 0;i < ist[x].size();i++ )

ans[x] += tongs[ d[x]+w[x]+maxn ] - buckets[x];

ans[x] += tongt[ w[x] - d[x]+maxn ] - buckett[x];

for( lint i = 0;i < ves[x].size();i++ )

for( lint i = 0;i < vet[x].size();i++ )

}int main()

build();

for( lint i = 1;i <= n;i++ ) scanf("%d",&w[i]);

for( lint x,y,i = 1;i <= m;i++ )

dfs(1,0);

for( lint i = 1;i <= n;i++ )

return 0;

}

洛谷 P1600 天天愛跑步

題面就不貼上了 把每個玩家的路徑拆成一條到lca的路徑和從lca到終點的路徑 然後,使用樹上差分統計答案即可 那麼,樹上差分是什麼?差分的具體思想是,當某區間內某元素對答案有貢獻,就在區間起點打乙個 1 標記代表多出了乙個對答案有貢獻的元素,在終點打乙個 1標記代表乙個對答案有貢獻的元素在該位置 結...

洛谷 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的連續正整數。...