BZOJ 4719: [Noip2016]天天爱跑步 线段树合并
title
BZOJ 4719
LUOGU 1600
簡化題意:
小c同學(xué)認(rèn)為跑步非常有趣,于是決定制作一款叫做《天天愛跑步》的游戲。《天天愛跑步》是一個養(yǎng)成類游戲,需要玩家每天按時(shí)上線,完成打卡任務(wù)。
這個游戲的地圖可以看作一一棵包含 \(n\) 個結(jié)點(diǎn)和 \(n-1\) 條邊的樹, 每條邊連接兩個結(jié)點(diǎn),且任意兩個結(jié)點(diǎn)存在一條路徑互相可達(dá)。樹上結(jié)點(diǎn)編號為從 \(1\) 到 \(n\) 的連續(xù)正整數(shù)。
現(xiàn)在有 \(m\) 個玩家,第 \(i\) 個玩家的起點(diǎn)為 \(S_i\) ,終點(diǎn)為 \(T_i\) 。每天打卡任務(wù)開始時(shí),所有玩家在第 \(0\) 秒同時(shí)從自己的起點(diǎn)出發(fā),以每秒跑一條邊的速度,不間斷地沿著最短路徑向著自己的終點(diǎn)跑去,跑到終點(diǎn)后該玩家就算完成了打卡任務(wù)。 (由于地圖是一棵樹,所以每個人的路徑是唯一的)
小c想知道游戲的活躍度,所以在每個結(jié)點(diǎn)上都放置了一個觀察員。 在結(jié)點(diǎn) \(j\) 的觀察員會選擇在第 \(W_j\) 秒觀察玩家,一個玩家能被這個觀察員觀察到當(dāng)且僅當(dāng)該玩家在第 \(W_j\) 秒也理到達(dá)了結(jié)點(diǎn) \(j\) 。 小C想知道每個觀察員會觀察到多少人?
注意:我們認(rèn)為一個玩家到達(dá)自己的終點(diǎn)后該玩家就會結(jié)束游戲,他不能等待一 段時(shí)間后再被觀察員觀察到。 即對于把結(jié)點(diǎn) \(j\) 作為終點(diǎn)的玩家:若他在第 \(W_j\) 秒前到達(dá)終點(diǎn),則在結(jié)點(diǎn) \(j\) 的觀察員不能觀察到該玩家;若他正好在第 \(W_j\) 秒到達(dá)終點(diǎn),則在結(jié)點(diǎn) \(j\) 的觀察員可以觀察到這個玩家。
analysis
對于一個人,他的路程會分為兩段,一段向上(根),一段向下,考慮在向上過程中他能產(chǎn)生貢獻(xiàn)的觀察者具有什么性質(zhì):設(shè)出發(fā)點(diǎn)深度為 \(dep[x]\),觀察者深度為 \(dep[y]\),觀察的時(shí)間為 \(t\),需滿足 \(dep[x]?dep[y]=t\),換句話說就是 \(dep[y]+t=dep[x]\) 。向下那一段的推導(dǎo)類似,下面的部分也只以向上的路徑為例來解釋。
現(xiàn)在我們記錄每個點(diǎn)下方出發(fā)點(diǎn)深度為 \(dep[x]\) 的人數(shù),需要對于每個出發(fā)點(diǎn)更新出發(fā)點(diǎn)到出發(fā)點(diǎn)與目的地的 \(lca\) 的所有點(diǎn),想到到開一顆權(quán)值線段樹,用線段樹合并不斷把信息往上傳,在 \(lca\) 處消除這次更新的影響,這樣一來直接我們就可以在樹上統(tǒng)計(jì)答案了。向下路徑的處理與向上路徑類似。
code
#include<bits/stdc++.h>const int maxn=3e5+10;namespace IO {char buf[1<<15],*fs,*ft;inline char getc() { return (ft==fs&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),ft==fs))?0:*fs++; }template<typename T>inline void read(T &x){x=0;T f=1, ch=getchar();while (!isdigit(ch) && ch^'-') ch=getchar();if (ch=='-') f=-1, ch=getchar();while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();x*=f;}char Out[1<<24],*fe=Out;inline void flush() { fwrite(Out,1,fe-Out,stdout); fe=Out; }template<typename T>inline void write(T x,char str){if (!x) *fe++=48;if (x<0) *fe++='-', x=-x;T num=0, ch[20];while (x) ch[++num]=x%10+48, x/=10;while (num) *fe++=ch[num--];*fe++=str;} }using IO::read; using IO::write;int ver[maxn<<1],Next[maxn<<1],head[maxn],len; inline void add(int x,int y) {ver[++len]=y,Next[len]=head[x],head[x]=len; }namespace SGT {struct Orz{int l,r,z;}c[maxn*60];int num=0;inline void Change(int &x,int l,int r,int k,int z){if (!x) x=++num;c[x].z+=z;if (l==r) return ;int mid=(l+r)>>1;if (k<=mid) Change(c[x].l,l,mid,k,z);else Change(c[x].r,mid+1,r,k,z);}inline int query(int x,int l,int r,int k){if (l==r) return c[x].z;int mid=(l+r)>>1;if (k<=mid) return query(c[x].l,l,mid,k);else return query(c[x].r,mid+1,r,k);}inline int merge(int x,int y){if (!x) return y;if (!y) return x;c[x].l=merge(c[x].l,c[y].l);c[x].r=merge(c[x].r,c[y].r);c[x].z=c[x].z+c[y].z;return x;} }using SGT::Change; using SGT::query; using SGT::merge;namespace lca {int dfn[maxn],id;int f[maxn][21],dep[maxn];inline void dfs(int x){dfn[x]=++id;for (int i=1; i<=20; ++i) f[x][i]=f[f[x][i-1]][i-1];for (int i=head[x]; i; i=Next[i]){int y=ver[i];if (y==f[x][0]) continue;f[y][0]=x;dep[y]=dep[x]+1;dfs(y);}}inline int LCA(int x,int y){if (dep[x]>dep[y]) std::swap(x,y);for (int i=20; i>=0; --i)if (dep[y]-(1<<i)>=dep[x]) y=f[y][i];if (x==y) return x;for (int i=20; i>=0; --i)if (f[x][i]^f[y][i]) x=f[x][i],y=f[y][i];return f[x][0];} }using lca::dfs; using lca::LCA; using lca::dep; using lca::f;int tot,n,m,u[maxn],v[maxn]; int ans[maxn],w[maxn]; inline void get(int x) {for (int i=head[x]; i; i=Next[i]){int y=ver[i];if (y==f[x][0]) continue;get(y);u[x]=merge(u[x],u[y]), v[x]=merge(v[x],v[y]);}ans[x]=query(u[x],1,tot,dep[x]+w[x])+query(v[x],1,tot,w[x]-dep[x]+n); }int main() {read(n);read(m); tot=n<<1;for (int i=1,x,y; i<n; ++i) read(x),read(y),add(x,y),add(y,x);for (int i=1; i<=n; ++i) read(w[i]);dfs(1);for (int i=1,x,y; i<=m; ++i){read(x),read(y);int a=LCA(x,y);Change(u[x],1,tot,dep[x],1);Change(u[a],1,tot,dep[x],-1);Change(v[y],1,tot,dep[x]-(dep[a]<<1)+n,1);Change(v[f[a][0]],1,tot,dep[x]-(dep[a]<<1)+n,-1);}get(1);for (int i=1; i<=n; ++i) write(ans[i],' '); *IO::fe--;//防 BZOJIO::flush();return 0; }轉(zhuǎn)載于:https://www.cnblogs.com/G-hsm/p/11426646.html
總結(jié)
以上是生活随笔為你收集整理的BZOJ 4719: [Noip2016]天天爱跑步 线段树合并的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ios 触摸事件 学习
- 下一篇: 容联云通讯Demo