一棵 \(n\) 個節點的樹, 樹的每個節點上有乙個觀察員, 每乙個觀察員的觀察時刻為 \(time_i\),
有 \(m\) 個玩家, 每個玩家在 \(0\) 時刻時從起點 \(s_i\) 開始跑步, 每時刻經過乙個節點, 沿著最短路徑向終點 \(t_i\) 跑去.
求每個觀察員能觀察到的玩家數量.
暴力列舉每個玩家的行進路線一定是 \(o(n^2)\) 的, 不可行,
那麼考慮列舉每乙個觀察員, 求它能觀察到多少個選手.
若觀察員 \(x\) 位於 \(s_i\) 到 \(lca_i\) 的路徑上, 那麼 \(x\) 能觀察到 \(i\) 的條件為
\[time_x = dep_ - dep_x
\]轉化一下變為,
\[time_x+dep_x = dep_
\]若 \(x\) 位於 \(t_i\) 到 \(lca_i\) 的路徑上, 那麼 \(x\) 能觀察到 \(i\) 的條件為
\[time_x = dis_ - (dep_t - dep_x)
\]轉化,
\[time_x - dep_x = dis - dep_t = dep_s - 2*dep_
\]看起來樹上差分, 列舉每個點的子樹, 開個桶記錄就好了.
但有個問題, 就是之前的桶會影響當前列舉到的點.
我的做法比較蠢, 先把整棵樹按照 $dfs$ 序排成乙個序列, 並建立樹狀陣列, 然後從小到大列舉差分值, 每次把所有差分值相同的點在 $dfs$ 序列上修改, 並讓所有滿足這個值的觀察員進行查詢.
其實我們考慮一下, 當前點需要的並不是整個桶, 只需要它自己的兩個值上面的值就行了.
所以我們列舉到每個點的時候先記錄一下它的兩個值, 然後列舉完它的子樹後, 再檢視它的兩個值, 求個差就行了.#include#define pb push_back
#define sz size
using namespace std;
const int n=299998+7;
const int l=20;
int n,m,dep[n],dfn[n],en[n],cnt,tme[n],f[n][l+7],ans[n],s[n],t[n],lca[n],qes[n],poi[n];
int t1[n],t2[n],c[n];
int lst[n],nxt[2*n],to[2*n],tot;
vectorp[n];
void add(int x,int y)
void pre(int u,int fa)
en[u]=cnt;
}int lca(int x,int y)
return f[x][0];
}bool rulea(int a,int b){ return tme[a]+dep[a]>n>>m;
int x,y;
for(int i=1;i有時間再補吧.
NOIP2016 天天愛跑步
時間限制 2 s 記憶體限制 512 mb 題目描述 小c同學認為跑步非常有趣,於是決定製作一款叫做 天天愛跑步 的遊戲。天天愛跑步 是乙個養成類遊戲,需要玩家每天按時上線,完成打卡任務。這個遊戲的地圖可以看作一棵包含n個結點和n 1條邊的樹,每條邊連線兩個結點,且任意兩個結點存在一條路徑互相可達。...
NOIP2016天天愛跑步
小c同學認為跑步非常有趣,於是決定製作一款叫做 天天愛跑步 的遊戲。天天愛跑步 是乙個養成類遊戲,需要玩家每天按時上線,完成打卡任務。這個遊戲的地圖可以看作一一棵包含 nn n個結點和 n 1n 1n 1條邊的樹,每條邊連線兩個結點,且任意兩個結點存在一條路徑互相可達。樹上結點編號為從11 1到nn...
NOIP2016 天天愛跑步
看這道題不爽很久了,但一直沒有開它,原因是我不會 我太菜了 看了題解還是寫不來,因為我不會線段樹合併。然後今天學了dsu on tree這種神奇的科技,成功把它a了,效率吊打線段樹合併。於是寫篇題解紀念一下。洛谷p1600 天天愛跑步 不帶修改的樹上路徑資訊的維護,很容易想到樹上差分。我們考慮一條路...