bzoj4719 Noip2016 天天愛跑步

2022-08-23 04:54:11 字數 3188 閱讀 5743

description

小c同學認為跑步非常有趣,於是決定製作一款叫做《天天愛跑步》的遊戲。?天天愛跑步?是乙個養成類遊戲,需要

玩家每天按時上線,完成打卡任務。這個遊戲的地圖可以看作一一棵包含 n個結點和n-1 條邊的樹, 每條邊連線兩

個結點,且任意兩個結點存在一條路徑互相可達。樹上結點編號為從1到n的連續正整數。現在有個玩家,第個玩家的

起點為si ,終點為ti 。每天打卡任務開始時,所有玩家在第0秒同時從自己的起點出發, 以每秒跑一條邊的速度,

不間斷地沿著最短路徑向著自己的終點跑去, 跑到終點後該玩家就算完成了打卡任務。 (由於地圖是一棵樹, 所以

每個人的路徑是唯一的)小c想知道遊戲的活躍度, 所以在每個結點上都放置了乙個觀察員。 在結點的觀察員會選

擇在第wj秒觀察玩家, 乙個玩家能被這個觀察員觀察到當且僅當該玩家在第wj秒也理到達了結點j 。 小c想知道

每個觀察員會觀察到多少人?注意: 我們認為乙個玩家到達自己的終點後該玩家就會結束遊戲, 他不能等待一 段時

間後再被觀察員觀察到。 即對於把結點j作為終點的玩家: 若他在第wj秒重到達終點,則在結點j的觀察員不能觀察

到該玩家;若他正好在第wj秒到達終點,則在結點的觀察員可以觀察到這個玩家。

input

第一行有兩個整數n和m 。其中n代表樹的結點數量, 同時也是觀察員的數量, m代表玩家的數量。

接下來n-1 行每行兩個整數u和v ,表示結點u 到結點v 有一條邊。

接下來一行n 個整數,其中第個整數為wj , 表示結點出現觀察員的時間。

接下來 m行,每行兩個整數si和ti,表示乙個玩家的起點和終點。

對於所有的資料,保證 。

1<=si,ti<=n,0<=wj<=n

output

輸出1行n 個整數,第個整數表示結點的觀察員可以觀察到多少人。

sample input

6 3

2 3

1 2

1 4

4 5

4 6

0 2 5 1 2 3

1 5

1 3

2 6sample output

2 0 0 1 1 1

hint

對於1號點,w1=0,故只有起點為1號點的玩家才會被觀察到,所以玩家1和玩家2被觀察到,共2人被觀察到。

對於2號點,沒有玩家在第2秒時在此結點,共0人被觀察到。

對於3號點,沒有玩家在第5秒時在此結點,共0人被觀察到。

對於4號點,玩家1被觀察到,共1人被觀察到。

對於5號點,玩家1被觀察到,共1人被觀察到。

對於6號點,玩家3被觀察到,共1人被觀察到

分析:

這道題好像和bzoj上有一道叫遊戲的樹剖題很像

每個人隨時間跑動很煩啊

如果我們先不管這些,那這些路線就變成了一條條覆蓋在樹上的樹鏈了

我們就可以用樹鏈剖分中的樹鏈加值搞一搞就好了

那我們現在考慮一下有

設t[i]是觀察時間

我們把一條樹鏈分成兩部分,左鏈和右鏈

右鏈中,能夠統計到的到達時間是

deep[s]-deep[i]=t[i],時間+深度是定值:deep[s]=deep[i]+t[i]

在左鏈中,能夠統計到的到達時間是

deep[i]+deep[s]-2*deep[lca]=t[i]

深度-時間是定值:2*deep[lca]-deep[s]=deep[i]-t[i]

這樣我們就可以分成到達時間上公升下降的兩段

說明一下上公升的樹鏈

將s到lca的路徑標上deep[s],

最後ans[i]就等於在i點上等於deep[i]+t[i]的標記的個數

但直接標記路徑上所有的點太慢,

我們可以在s點打上+1的標記,lca點打上-1的標記,然後dfs做求子樹和,

為避免將其它子樹的和計入ans,

只要記錄進入這個點時的cnt[deep[i]+t[i]],

訪問完這個點後用新的cnt[deep[i]+t[i]]減去進來的就可以了

這裡寫**片

#include

#include

#include

#include

using namespace std;

const int n=500050;

int n,m;

struct nd;

nd way[n<<1];

struct node;

node t[n<<2];

int deep[n],size[n],pre[n],son[n],top[n],num[n],shu[n],cnt=0,tot=0,dfn[n];

struct nod;

nod q[n];

int t[n],ans[n],tong[n<<1],tong2[n<<1],st[n];

vector a[n],b[n],c[n];

void add(int u,int w)

void dfs1(int now,int fa,int dep)

}}void dfs2(int now,int fa) }

int lca(int u,int w)

void dfs_up(int

x,int fa)

void dfs_down(int

x,int fa)

int main()

dfs1(1,0,1);

dfs2(1,0);

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

for (int i=1;i<=m;i++)

dfs_up(1,0);

for (int i=1;i<=m;i++)

dfs_down(1,0);

for (int i=1;i<=m;i++) if (deep[q[i].s]-deep[q[i].lca]==t[q[i].lca]) ans[q[i].lca]--;

printf("%d",ans[1]);

for(int i=2;i<=n;i++) printf(" %d",ans[i]);

return

0;}

BZOJ4719 Noip2016 天天愛跑步

考慮鏈上做法,發現就是把每個路徑拆成一次加入和一次刪除,然後從前往後掃,走一步所有路徑經過當前點的時間就要麼加一,要麼減一,且要麼是一直加一,要麼是一直減一,可以用兩個陣列和指標來維護整體加減 用鏈剖把乙個區間轉換成o log n 個區間,即可在樹上做 include include include...

BZOJ4719 Noip2016 天天愛跑步

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

NOIP2016 bzoj4719天天愛跑步

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