NOIP2016 天天爱跑步 (LCA,树上差分)
2017-10-13 20:52
351 查看
Description
小c同学认为跑步非常有趣,于是决定制作一款叫做《天天爱跑步》的游戏。«天天爱跑步»是一个养成类游戏,需要玩家每天按时上线,完成打卡任务。这个游戏的地图可以看作一一棵包含n个结点和n−1条边的树, 每条边连接两个结点,且任意两个结点存在一条路径互相可达。树上结点编号为从1到n的连续正整数。现在有m个玩家,第ii个玩家的起点为 Si ,终点为Ti。每天打卡任务开始时,所有玩家在第0秒同时从自己的起点出发, 以每秒跑一条边的速度, 不间断地沿着最短路径向着自己的终点跑去, 跑到终点后该玩家就算完成了打卡任务。 (由于地图是一棵树, 所以每个人的路径是唯一的)小C想知道游戏的活跃度, 所以在每个结点上都放置了一个观察员。 在结点jj的观察员会选择在第Wj秒观察玩家, 一个玩家能被这个观察员观察到当且仅当该玩家在第Wj秒也理到达了结点j。小C想知道每个观察员会观察到多少人?
(注意: 我们认为一个玩家到达自己的终点后该玩家就会结束游戏, 他不能等待一 段时间后再被观察员观察到。 即对于把结点j作为终点的玩家: 若他在第Wj秒钟到达终点,则在结点j的观察员不能观察到该玩家;若他正好在第Wj秒到达终点,则在结点j的观察员可以观察到这个玩家。)
Solution
将每条Si到Ti的路径分成两条,Si到lca,lca到Ti。对于第一条,以u为起点的路径能够被路径上的i点观测到当且仅当dep[u]−dep[i]=w[i],移项得:dep[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; }
相关文章推荐
- 【BZOJ】4719 [Noip2016]天天爱跑步 LCA+树上差分
- NOIP2016 day1T2--BZOJ4719 天天爱跑步--LCA+差分
- 【NOIP2016】天天爱跑步——LCA+树上差分
- 【NOIP2016】【LCA】【树上差分】【史诗级难度】天天爱跑步
- 【NOIP2016提高组T2】天天爱跑步-倍增LCA+树上差分
- [NOIP2016] 天天爱跑步 LCA 树上差分 线段树
- NOIP2016 天天爱跑步 TarjanLCA+树上差分
- UOJ 261/bzoj 4719(LCA)(NOIP2016)(天天爱跑步)
- bzoj4719 [Noip2016]天天爱跑步(树+lca+树上差分+思路题)
- NOIP2016 Day2 T2 天天爱跑步(树上差分)
- 【NOIP2016】天天爱跑步(树上差分)
- 【NOIP2016】天天爱跑步之树上差分
- BZOJ4719(NOIP2016)[天天爱跑步]--LCA+DFS
- ☆ [NOIp2016] 天天爱跑步 「树上差分」
- Noip2016 天天爱跑步【LCA】【差分】
- [Noip2016]天天爱跑步 LCA+DFS
- bzoj 4719: [Noip2016]天天爱跑步【树上差分+dfs】
- 【BZOJ 3631】松鼠的新家 【LCA+树上差分】
- NOIP2015 运输计划 二分答案+Tarjan LCA+树上差分
- 洛谷P3345 [ZJOI2015]幻想乡战略游戏(动态点分治,树的重心,二分查找,Tarjan-LCA,树上差分)