1. 程式人生 > >NOIP2016 天天愛跑步 (LCA,樹上差分)

NOIP2016 天天愛跑步 (LCA,樹上差分)

Description

小c同學認為跑步非常有趣,於是決定製作一款叫做《天天愛跑步》的遊戲。«天天愛跑步»是一個養成類遊戲,需要玩家每天按時上線,完成打卡任務。
這個遊戲的地圖可以看作一一棵包含n個結點和n1條邊的樹, 每條邊連線兩個結點,且任意兩個結點存在一條路徑互相可達。樹上結點編號為從1n的連續正整數。現在有m個玩家,第ii個玩家的起點為 Si​​ ,終點為Ti​​。每天打卡任務開始時,所有玩家在第0秒同時從自己的起點出發, 以每秒跑一條邊的速度, 不間斷地沿著最短路徑向著自己的終點跑去, 跑到終點後該玩家就算完成了打卡任務。 (由於地圖是一棵樹, 所以每個人的路徑是唯一的)小C想知道遊戲的活躍度, 所以在每個結點上都放置了一個觀察員。 在結點jj的觀察員會選擇在第W

j秒觀察玩家, 一個玩家能被這個觀察員觀察到當且僅當該玩家在第Wj秒也理到達了結點j。小C想知道每個觀察員會觀察到多少人?
(注意: 我們認為一個玩家到達自己的終點後該玩家就會結束遊戲, 他不能等待一 段時間後再被觀察員觀察到。 即對於把結點j作為終點的玩家: 若他在第Wj秒鐘到達終點,則在結點j的觀察員不能觀察到該玩家;若他正好在第Wj秒到達終點,則在結點j的觀察員可以觀察到這個玩家。)

Solution

將每條SiTi的路徑分成兩條,SilcalcaTi
對於第一條,以u為起點的路徑能夠被路徑上的i點觀測到當且僅當dep[u]dep[i]=w[i],移項得:de

p[i]+w[i]=dep[u],發現對於每個點來說dep[i]+w[i]是一個定值。所以可以進行深搜,遍歷到Si時將其dep[i]放進一個桶,回溯到lcai時,將Si的貢獻丟出去。每個點的答案就是dep[u]+w[u]所對應的桶。
第二種路徑也同理了。。

Code

#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector> #include<set> #define For(i , j , k) for (int i = (j) , _##end_ = (k) ; i <= _##end_ ; ++ i) #define Fordown(i , j , k) for (int i = (j) , _##end_ = (k) ; i >= _##end_ ; -- i) #define Set(a , b) memset(a , b , sizeof(a)) #define pb push_back #define INF (0x3f3f3f3f) #define Mod (1000000007) using namespace std; typedef long long LL; template <typename T> inline bool chkmax(T &a , T b) { return a < b ? (a = b , 1) : 0; } template <typename T> inline bool chkmin(T &a , T b) { return b < a ? (a = b , 1) : 0; } int _ , __; char c_; inline int read() { for (_ = 0 , __ = 1 , c_ = getchar() ; !isdigit(c_) ; c_ = getchar()) if (c_ == '-') __ = -1; for ( ; isdigit(c_) ; c_ = getchar()) _ = (_ << 1) + (_ << 3) + (c_ ^ 48); return _ * __; } inline void file() { #ifdef hany01 freopen("running.in" , "r" , stdin); freopen("running.out" , "w" , stdout); #endif } const int maxn = 300010; struct Question { int s , t , lca , len; }q[maxn]; int n , m , v[maxn * 2] , nex[maxn * 2] , beg[maxn] , e , fa[maxn][22] , ans[maxn] , va[maxn] , bkt[maxn * 2] , dep[maxn] , w[maxn] , log2n; vector<int> vct1[maxn] , vct2[maxn]; inline void add_edge(int uu , int vv) { v[++ e] = vv; nex[e] = beg[uu]; beg[uu] = e; } void Init_LCA(int u , int pa) { for (int i = beg[u] ; i ; i = nex[i]) { if (pa == v[i]) continue; fa[v[i]][0] = u; dep[v[i]] = dep[u] + 1; Init_LCA(v[i] , u); } } inline int LCA(int u , int v) { if (dep[u] < dep[v]) swap(u , v); register int dt = dep[u] - dep[v]; Fordown(i , log2n , 0) if (dt >= (1 << i)) { dt -= (1 << i); u = fa[u][i]; } if (u == v) return u; Fordown(i , log2n , 0) if (fa[u][i] != fa[v][i]) { u = fa[u][i]; v = fa[v][i]; } return fa[u][0]; } void Init() { static int uu , vv; n = read(); m = read(); For(i , 2 , n) uu = read(), vv = read(), add_edge(uu , vv), add_edge(vv , uu); For(i , 1 , n) w[i] = read(); dep[1] = 1; Init_LCA(1 , 1); log2n = (int)log(n * 1.0000) / log(2.0000) + 1; For(i , 1 , log2n) For(j , 1 , n) fa[j][i] = fa[fa[j][i - 1]][i - 1]; For(i , 1 , m) { q[i].s = read(); q[i].t = read(); q[i].lca = LCA(q[i].s , q[i].t); q[i].len = dep[q[i].s] + dep[q[i].t] - dep[q[i].lca] * 2; if (dep[q[i].s] - dep[q[i].lca] == w[q[i].lca]) -- ans[q[i].lca]; } } void dfs1(int u) { register int ht = 0; if (dep[u] + w[u] <= n) ht = bkt[dep[u] + w[u]]; for (register int i = beg[u] ; i ; i = nex[i]) { if (fa[v[i]][0] != u) continue; dfs1(v[i]); } bkt[dep[u]] += va[u]; if (dep[u] + w[u] <= n) ans[u] += bkt[dep[u] + w[u]] - ht; For(i , 0 , vct1[u].size() - 1) -- bkt[dep[vct1[u][i]]]; } void dfs2(int u) { register int ht; ht = bkt[dep[u] - w[u] + n]; for (register int i = beg[u] ; i ; i = nex[i]) { if (fa[v[i]][0] != u) continue; dfs2(v[i]); } For(i , 0 , vct1[u].size() - 1) { ++ bkt[vct1[u][i] + n]; } ans[u] += bkt[dep[u] - w[u] + n] - ht; For(i , 0 , vct2[u].size() - 1) { -- bkt[vct2[u][i] + n]; } } inline void Solve() { For(i , 1 , m) { ++ va[q[i].s]; vct1[q[i].lca].pb(q[i].s); } dfs1(1); Set(bkt , 0); For(i , 1 , n) vct1[i].clear(); For(i , 1 , m) { vct1[q[i].t].pb(dep[q[i].t] - q[i].len); vct2[q[i].lca].pb(dep[q[i].t] - q[i].len); } dfs2(1); For(i , 1 , n) printf("%d " , ans[i]); } int main() { file(); Init(); Solve(); return 0; }