#261. 【NOIP2016】天天愛跑步
小C同學認為跑步非常有趣,於是決定制作一款叫做《天天愛跑步》的游戲。《天天愛跑步》是一個養成類游戲,需要玩家每天按時上線,完成打卡任務。
這個游戲的地圖可以看作一棵包含 nn 個結點和 n−1n−1 條邊的樹,每條邊連接兩個結點,且任意兩個結點存在一條路徑互相可達。樹上結點編號為從 11 到 nn 的連續正整數。
現在有 mm 個玩家,第 ii 個玩家的起點為 SiSi,終點為 TiTi。每天打卡任務開始時,所有玩家在第 00 秒同時從自己的起點出發,以每秒跑一條邊的速度,不間斷地沿着最短路徑向着自己的終點跑去,跑到終點后該玩家就算完成了打卡任務。(由於地圖是一棵樹,所以每個人的路徑是唯一的)
小C想知道游戲的活躍度,所以在每個結點上都放置了一個觀察員。在結點 jj 的觀察員會選擇在第 WjWj 秒觀察玩家,一個玩家能被這個觀察員觀察到當且僅當該玩家在第 WjWj 秒也正好到達了結點 jj。小C想知道每個觀察員會觀察到多少人?
注意:我們認為一個玩家到達自己的終點后該玩家就會結束游戲,他不能等待一段時間后再被觀察員觀察到。即對於把結點 jj 作為終點的玩家:若他在第 WjWj 秒前到達終點,則在結點 jj 的觀察員不能觀察到該玩家;若他正好在第 WjWj 秒到達終點,則在結點 jj 的觀察員可以觀察到這個玩家。
輸入格式
從標准輸入讀入數據。
第一行有兩個整數 nn 和 mm。其中 nn 代表樹的結點數量,同時也是觀察員的數量,mm 代表玩家的數量。
接下來 n−1n−1 行每行兩個整數 uu 和 vv,表示結點 uu 到結點 vv 有一條邊。
接下來一行 nn 個整數,其中第 jj 個整數為 WjWj,表示結點 jj 出現觀察員的時間。
接下來 mm 行,每行兩個整數 SiSi 和 TiTi,表示一個玩家的起點和終點。
對於所有的數據,保證 1≤Si,Ti≤n1≤Si,Ti≤n,0≤Wj≤n0≤Wj≤n。
輸出格式
輸出到標准輸出。
輸出 11 行 nn 個整數,第 jj 個整數表示結點 jj 的觀察員可以觀察到多少人。
樣例一
input
6 3 2 3 1 2 1 4 4 5 4 6 0 2 5 1 2 3 1 5 1 3 2 6
output
2 0 0 1 1 1
explanation
對於 11 號點,W1=0W1=0,故只有起點為 11 號點的玩家才會被觀察到,所以玩家 11 和玩家 22 被觀察到,共 22 人被觀察到。
對於 22 號點,沒有玩家在第 22 秒時在此結點,共 00 人被觀察到。
對於 33 號點,沒有玩家在第 55 秒時在此結點,共 00 人被觀察到。
對於 44 號點,玩家 11 被觀察到,共 11 人被觀察到。
對於 55 號點,玩家 11 被觀察到,共 11 人被觀察到。
對於 66 號點,玩家 33 被觀察到,共 11 人被觀察到。
樣例二
input
5 3 1 2 2 3 2 4 1 5 0 1 0 3 0 3 1 1 4 5 5
output
1 2 1 0 1
限制與約定
每個測試點的數據規模及特點如下表所示。提示:數據范圍的個位上的數字可以幫助判斷是哪一種數據類型。
測試點編號 | nn | mm | 約定 |
---|---|---|---|
1 | =991=991 | =991=991 | 所有人的起點等於自己的終點,即 Si=TiSi=Ti |
2 | |||
3 | =992=992 | =992=992 | Wj=0Wj=0 |
4 | |||
5 | =993=993 | =993=993 | 無 |
6 | =99994=99994 | =99994=99994 | 樹退化成一條鏈,其中 11 與 22 有邊,22 與 33 有邊,……,n−1n−1 與 nn 有邊 |
7 | |||
8 | |||
9 | =99995=99995 | =99995=99995 | 所有的 Si=1Si=1 |
10 | |||
11 | |||
12 | |||
13 | =99996=99996 | =99996=99996 | 所有的 Ti=1Ti=1 |
14 | |||
15 | |||
16 | |||
17 | =99997=99997 | =99997=99997 | 無 |
18 | |||
19 | |||
20 | =299998=299998 | =299998=299998 |
時間限制:2s2s
空間限制:512MB512MB
下載
2017-04-06
蒟蒻一只,只會用樹刨求lca(貌似倍增也會),tarjan就不會了。
由於我用數據結構維護子樹的差分和是nlogn的,lca復雜度不高於nlogn即可。
參照:http://www.cnblogs.com/shenben/p/6246450.html
#include<cstdio> #include<cstring> #include<algorithm> #define m(s) memset(s,0,sizeof s); using namespace std; const int N=3e5+5,M=N*23; int n,m,w[N],t[N],ans[N]; int dfn_cnt,le[N],ri[N]; int dep[N],fa[N],son[N],siz[N],top[N]; int sz,root[N*3],ls[M],rs[M]; int sum[M]; struct data{int s,t,lca;}d[N]; struct edge{int v,next;}e[N<<1];int tot,head[N]; inline int read(){ int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } inline void add(int x,int y){ e[++tot].v=y;e[tot].next=head[x];head[x]=tot; e[++tot].v=x;e[tot].next=head[y];head[y]=tot; } void dfs(int x,int f,int de){ le[x]=++dfn_cnt; fa[x]=f;dep[x]=de;siz[x]=1; for(int i=head[x];i;i=e[i].next){ if(e[i].v!=f){ dfs(e[i].v,x,de+1); siz[x]+=siz[e[i].v]; if(siz[son[x]]<siz[e[i].v]) son[x]=e[i].v; } } ri[x]=dfn_cnt; } void gettop(int x,int tp){ top[x]=tp; if(!son[x]) return ; gettop(son[x],tp); for(int i=head[x];i;i=e[i].next){ if(e[i].v!=fa[x]&&e[i].v!=son[x]){ gettop(e[i].v,e[i].v); } } } int lca(int x,int y){ for(;top[x]!=top[y];x=fa[top[x]]){ if(dep[top[x]]<dep[top[y]]) swap(x,y); } return dep[x]<dep[y]?x:y; } void change(int &k,int l,int r,int p,int v){ if(!p) return ; if(!k) k=++sz; sum[k]+=v; if(l==r) return ; int mid=l+r>>1; if(p<=mid) change(ls[k],l,mid,p,v); else change(rs[k],mid+1,r,p,v); } int query(int k,int l,int r,int x,int y){ if(!k) return 0; if(l==x&&r==y) return sum[k]; int mid=l+r>>1; if(y<=mid) return query(ls[k],l,mid,x,y); else if(x>mid) return query(rs[k],mid+1,r,x,y); else return query(ls[k],l,mid,x,mid)+query(rs[k],mid+1,r,mid+1,y); } void Clear(){ sz=0;m(root);m(ls);m(rs);m(sum); } int main(){ n=read();m=read(); for(int i=1,x,y;i<n;i++) x=read(),y=read(),add(x,y); for(int i=1;i<=n;i++) w[i]=read(); dfs(1,1,1);gettop(1,1); for(int i=1;i<=m;i++){ d[i].s=read();d[i].t=read(); d[i].lca=lca(d[i].s,d[i].t); } fa[1]=0; for(int i=1;i<=n;i++) t[i]=w[i]+dep[i]; for(int i=1,now;i<=m;i++){ now=dep[d[i].s]; change(root[now],1,n,le[d[i].s],1); change(root[now],1,n,le[fa[d[i].lca]],-1); } for(int i=1;i<=n;i++) ans[i]+=query(root[t[i]],1,n,le[i],ri[i]); Clear(); for(int i=1;i<=n;i++) t[i]=w[i]-dep[i]+n+1; for(int i=1,now;i<=m;i++){ now=dep[d[i].s]-(dep[d[i].lca]<<1)+n+1; change(root[now],1,n,le[d[i].t],1); change(root[now],1,n,le[d[i].lca],-1); } for(int i=1;i<=n;i++) ans[i]+=query(root[t[i]],1,n,le[i],ri[i]); for(int i=1;i<=n;i++) printf("%d ",ans[i]); return 0; }