描述
小c同學認為跑步非常有趣,於是決定製作一款叫做《天天愛跑步》的遊戲。《天天愛跑步》是乙個養成類遊戲,需要玩家每天按時上線,完成打卡任務。
這個遊戲的地圖可以看作一棵包含n個結點和n - 1條邊的樹,每條邊連線兩個結點,且任意兩個結點存在一條路徑互相可達。樹上結點編號為從1到n的連續正整數。
現在有m個玩家,第i個玩家的起點為si,終點為ti。每天打卡任務開始時,所有玩家 在第0秒 同時從 自己的起點 出發,以 每秒跑一條邊 的速度,不間斷地沿著最短路徑向著 自己的終點 跑去,跑到終點後該玩家就算完成了打卡任務。(由於地圖是一棵樹,所以每個人的路徑是唯一的)
小c想知道遊戲的活躍度,所以在每個結點上都放置了乙個觀察員。在結點j的觀察員會選擇在第wj秒觀察玩家,乙個玩家能被這個觀察員觀察到當且僅當該玩家在第wj秒也 正好 到達了結點j。小c想知道每個觀察員會觀察到多少人?
注意: 我們認為乙個玩家到達自己的終點後該玩家就會結束遊戲,他不能等待一段時間後再被觀察員觀察到。即對於把結點j作為終點的玩家:若他在第wj秒前到達 終點,則在結點j的觀察員 不能觀察到 該玩家;若他 正好 在第wj秒到達終點,則在結點j的觀察員 可以觀察到 這個玩家。
格式輸入格式
第一行有兩個整數n和m。其中n代表樹的結點數量,同時也是觀察員的數量, m代表玩家的數量。
接下來n - 1行每行兩個整數u和v,表示結點u到結點v有一條邊。
接下來一行n個整數,其中第j個整數為wj,表示結點j出現觀察員的時間。 接下來m行,每行兩個整數si和ti,表示乙個玩家的起點和終點。
對於所有的資料,保證1
<= si, ti <= n,0
<= wj <= n。
輸出格式
輸出1行n個整數,第j個整數表示結點j的觀察員可以觀察到多少人。
樣例1樣例輸入163
2312
1445
4602
5123
1513
26copy
樣例輸出120
0111
copy
樣例2樣例輸入253
1223
2415
0103
0311
455copy
樣例輸出212
101copy
限制每個測試點時限2秒。
【子任務】
提示【樣例1說明】
對於1號點,w1=0,故只有起點為1號點的玩家才會被觀察到,所以玩家1和玩家2被觀察到,共2人被觀察到。
對於2號點,沒有玩家在第2秒時在此結點,共0人被觀察到。
對於3號點,沒有玩家在第5秒時在此結點,共0人被觀察到。
對於4號點,玩家1被觀察到,共1人被觀察到。
對於5號點,玩家2被觀察到,共1人被觀察到。
對於6號點,玩家3被觀察到,共1人被觀察到。
**noip 2016 提高組 day 1 第二題
1、思路:lca + 路徑分解 + 線段樹
2、約定:
s:起點
t:終點
lca:s,t的最近公共祖先
w:題目中的w
dep:結點的深度
ans:結點i的答案
3、事實:
(1)s->lca : w[i]+dep[i]=dep[s]
t->lca : w[i]-dep[i]+大整數=dep[s]-2*dep[lca]+大整數
(2)ans[i] = | | + | |
4、過程:
dfs:獲得樹的基本資訊
lca:計算s,t的公共祖先
(1)將鏈以lca為分界點斷開。實現時應注意細節。
(2)for x 的兒子child != x的父親
——(2.1)訪問結點child
(3)將在x開始的路徑加入兩個線段樹
(4)記錄此時ans[x]的值為ans2
(5)ans[x] = ans2 - ans1(排除其它子樹對結果的影響)
(6)將在x結束的路徑移出兩個線段樹
*黑體字是較難想到的,也是此題難點。
5、時間複雜度:o(nlogn)
6、反思
(1)矛盾的特殊性寓於普遍性中:s->lca : w[i]+dep[i]=dep[s]
;t->lca : w[i]-dep[i]+大整數=dep[s]-2*dep[lca]+大整數
(2)通過與已有的模型比較發現矛盾的特殊性:lca兩側路徑方向不同,想到拆路徑。為了用rmq將等式變數分開到等號兩側。
(3)排除其它子樹的影響:應用字首和的思想。
(4)曾經的錯誤:未排除子樹的影響;值域rmq的值域範圍給小了;lca的細節。
#include
#include
#include
#include
#include
#include
#include
using
namespace
std;
const
int maxn = 300000 + 10;
const
int val = maxn * 2;
inline
int read()
return x;
}int n;
int w[maxn]; //觀察員出現時間
int f[maxn][40]; //倍增陣列
int dep[maxn]; //結點的深度
int ans[maxn]; //第i個結點的答案
vector
map[maxn], node[maxn], node2[maxn], node3[maxn], node4[maxn];
void dfs(int x, int fa, int depth)
}int lca1;
int lca(int l, int r)
struct rmq
void update(int l, int r, int id, int x, int add)
int mid = l + r >> 1;
if (x <= mid) update(l, mid, id << 1, x, add);
else update(mid + 1, r, (id << 1) + 1, x, add);
tree[id] = tree[id << 1] + tree[(id << 1) + 1];
}int query(int l, int r, int id, int x)
}rmq, rmq2;
/* node4[x] : x有開始跑的人的dep(s)
node3[x] : x有跑到的人的dep(s) - 2*dep(lca) + maxn
node2[lca] : dep(s) - 2*dep(lca) + maxn
node [lca] : dep(s)
*/void dfs2(int x, int fa)
for (int i = 0; i < node4[x].size(); ++i)
rmq.update(0, maxn, 1, node4[x][i], 1);
for (int i = 0; i < node3[x].size(); ++i)
rmq2.update(0, val, 1, node3[x][i], 1);
ans[x] += rmq.query(0, maxn, 1, w[x]+dep[x]) + rmq2.query(0, val, 1, w[x]-dep[x]+maxn);
for (int i = 0; i < node[x].size(); ++i)
rmq.update(0, maxn, 1, node[x][i], -1);
for (int i = 0; i < node2[x].size(); ++i)
rmq2.update(0, val, 1, node2[x][i], -1);
}int main()
for (int i = 1; i <= n; ++i)
w[i] = read();
dfs(1, -1, 1);
for (int i = 1; i <= 30; ++i)
for (int j = 1; j <= n; ++j)
f[j][i] = f[f[j][i-1]][i-1];
for (int i = 1; i <= m; ++i)
dfs2(1, -1);
for (int i = 1; i <= n; ++i)
printf("%d ", ans[i]);
return
0;}
也許,是乙個新的開始的時候了,無論何人何時何地。 天天愛跑步 noip2016day1t2
2016年考到一片oier的題目。利用樹上的差分來解決這個問題 先求出兩個節點的lca,然後分成向上跑和向下跑兩個鏈。向上從起點跑到lca,這個過程累加,過了lca,對統計的貢獻就沒有了,減掉。因此就結點來說統計乙個節點有多少人,就觀察點i來說,如果觀察點的值是wi,需要統計觀察點下方deep i ...
組合數問題 NOIP 2016 Day2 T1
題目描述 組合數 表示的是從n個物品中選出m個物品的方案數。舉個例子,從 1,2,3 三個物品中選擇兩個物品可以有 1,2 1,3 2,3 這三種選擇方法。根據組合數的定 義,我們可以給出計算組合數的一般公式 cm n n m n m 其中n 1 2 n 小蔥想知道如果給定n,m和k,對於所有的0 ...
noip 2016 day1 T1玩具謎題
小南有一套可愛的玩具小人,它們各有不同的職業。有一天,這些玩具小人把小南的眼鏡藏了起來。小南發現玩具小人們圍成了乙個圈,它們有的面朝圈內,有的面朝圈外。如下圖 這時singer告訴小南乙個謎題 眼鏡藏在我左數第3個玩具小人的右數第1個玩具小人的左數第2個玩具小人那裡。小南發現,這個謎題中玩具小人的朝...