NOIP2016 DAY1T2 天天愛跑步

2021-08-10 05:46:07 字數 4500 閱讀 6406

描述

小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個玩具小人那裡。小南發現,這個謎題中玩具小人的朝...