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

NOIP2016 天天愛跑步 (樹上差分+dfs)

產生 using cto continue 有一個 swa http get bug

題目大意:給你一顆樹,樹上每個點都有一個觀察員,他們僅會在 w[i] 時刻出現,觀察正在跑步的玩家

一共有m個玩家,他們分別從節點 s[i] 同時出發,以每秒跑一條邊的速度,沿著到 t[i] 的唯一路徑向節點t[i]奔跑

如果一名玩家已經到達了終點,那麽在他到達終點之後出現在終點的觀察員不會觀察到他

但如果在到達終點的同時觀察員也出現在終點,那麽觀察員可以觀察到他

求每個節點的觀察員觀察到玩家的數量

對於每個玩家的奔跑路線,可以拆成兩部分

<1>向上跑,從 u 向 lca 奔跑

顯然,玩家 u 能對觀察員 i 產生1點貢獻的充要條件為

技術分享圖片

顯然,向上走的路線能對 i 點產生共貢獻的條件是,起點 u 在 i 的子樹中

我們只需要統計符合條件的技術分享圖片即可

<2>向下跑,從 lca 向 v 奔跑

那麽顯然技術分享圖片

推導可得技術分享圖片

顯然,向下走的路線能對i點產生共貢獻的條件是,終點 v 在 i 的子樹中

類似於上面的方法,我們只需要統計符合條件的技術分享圖片即可

我們可以用vector在u,v,lca這三個點上打差分,存符合條件的值,註意值可能為負數

而其他子樹的結果會影響答案,所以深搜統計一次答案,再用回溯的答案減去深搜的答案即可

方法比較奇葩大家湊合看吧。。。

  1 #include <cstdio>
  2 #include <algorithm>
  3 #include <cstring>
  4
#include <vector> 5 #define N 300010 6 #define maxn 300000 7 using namespace std; 8 9 int n,m,cte; 10 int dep[N],fa[N],tp[N],sz[N],son[N],ans[N]; 11 int w[N],s[N],t[N],F[N],bac[N*3],head[N],tmp[N]; 12 struct EDGE{ 13 int to,nxt; 14 }edge[N*2]; 15 vector<int>S[N]; 16 vector<int
>E[N]; 17 int gc() 18 { 19 int rett=0,fh=1;char p=getchar(); 20 while(p<0||p>9) {if(p==-)fh=-1;p=getchar();} 21 while(p>=0&&p<=9) {rett=rett*10+p-0;p=getchar();} 22 return rett*fh; 23 } 24 void edge_add(int u,int v) 25 { 26 cte++; 27 edge[cte].to = v; 28 edge[cte].nxt=head[u]; 29 head[u]=cte; 30 } 31 void Tsp1(int u,int dad) 32 { 33 for(int j=head[u];j!=-1;j=edge[j].nxt) 34 { 35 int v=edge[j].to; 36 if(v==dad) continue; 37 dep[v]=dep[u]+1; 38 fa[v]=u; 39 Tsp1(v,u); 40 if(sz[v]>sz[son[u]]) son[u]=v; 41 sz[u]+=sz[v]; 42 } 43 sz[u]++; 44 } 45 void Tsp2(int u) 46 { 47 if(son[u]) tp[son[u]]=tp[u],Tsp2(son[u]); 48 for(int j=head[u];j!=-1;j=edge[j].nxt) 49 { 50 int v=edge[j].to; 51 if(v==fa[u]||v==son[u]) continue; 52 tp[v]=v; 53 Tsp2(v); 54 } 55 } 56 int LCA(int x,int y) 57 { 58 while(tp[x]!=tp[y]) 59 { 60 if(dep[tp[x]]<dep[tp[y]]) swap(x,y); 61 x=fa[tp[x]]; 62 } 63 return dep[x]<=dep[y]?x:y; 64 } 65 void dfs1(int u) 66 { 67 tmp[u]=bac[dep[u]+w[u]+maxn]; 68 for(int j=head[u];j!=-1;j=edge[j].nxt) 69 { 70 int v=edge[j].to; 71 if(v==fa[u]) continue; 72 dfs1(v); 73 } 74 for(int i=0;i<S[u].size();i++) 75 bac[S[u][i]+maxn]++; 76 ans[u]+=bac[dep[u]+w[u]+maxn]-tmp[u]; 77 for(int i=0;i<E[u].size();i++) 78 bac[E[u][i]+maxn]--; 79 } 80 void dfs2(int u) 81 { 82 tmp[u]=bac[w[u]-dep[u]+maxn]; 83 for(int j=head[u];j!=-1;j=edge[j].nxt) 84 { 85 int v=edge[j].to; 86 if(v==fa[u]) continue; 87 dfs2(v); 88 } 89 for(int i=0;i<E[u].size();i++) 90 bac[E[u][i]+maxn]--; 91 for(int i=0;i<S[u].size();i++) 92 bac[S[u][i]+maxn]++; 93 ans[u]+=bac[w[u]-dep[u]+maxn]-tmp[u]; 94 } 95 96 int main() 97 { 98 freopen("running1.in","r",stdin); 99 //freopen("running6.out","w",stdout); 100 scanf("%d%d",&n,&m); 101 int x,y; 102 memset(head,-1,sizeof(head)); 103 for(int i=1;i<n;i++) 104 { 105 x=gc(),y=gc(); 106 edge_add(x,y); 107 edge_add(y,x); 108 } 109 tp[1]=1; 110 Tsp1(1,-1); 111 Tsp2(1); 112 for(int i=1;i<=n;i++) w[i]=gc(); 113 for(int i=1;i<=m;i++) 114 { 115 s[i]=gc(),t[i]=gc(); 116 F[i]=LCA(s[i],t[i]); 117 S[s[i]].push_back(dep[s[i]]); 118 E[F[i]].push_back(dep[s[i]]); 119 } 120 //debug(); 121 dfs1(1); 122 for(int i=1;i<=n;i++) 123 { 124 S[i].clear(),E[i].clear(); 125 } 126 memset(tmp,0,sizeof(tmp)); 127 for(int i=1;i<=m;i++) 128 { 129 S[t[i]].push_back(dep[s[i]]-2*dep[F[i]]); 130 E[F[i]].push_back(dep[s[i]]-2*dep[F[i]]); 131 } 132 dfs2(1); 133 for(int i=1;i<=n;i++) printf("%d ",ans[i]); 134 return 0; 135 }

NOIP2016 天天愛跑步 (樹上差分+dfs)