NOIP2016 天天愛跑步(線段樹/桶)
題目描述
小c同學認為跑步非常有趣,於是決定制作一款叫做《天天愛跑步》的遊戲。天天愛跑步是一個養成類遊戲,需要 玩家每天按時上線,完成打卡任務。
這個遊戲的地圖可以看作一一棵包含 N個結點和N-1 條邊的樹, 每條邊連接兩個結點,且任意兩個結點存在一條路徑互相可達。樹上結點編號為從1到N的連續正整數。
現在有個玩家,第個玩家的 起點為Si ,終點為Ti 。每天打卡任務開始時,所有玩家在第0秒同時從自己的起點出發, 以每秒跑一條邊的速度, 不間斷地沿著最短路徑向著自己的終點跑去, 跑到終點後該玩家就算完成了打卡任務。 (由於地圖是一棵樹, 所以 每個人的路徑是唯一的)
小C想知道遊戲的活躍度, 所以在每個結點上都放置了一個觀察員。 在結點的觀察員會選 擇在第Wj秒觀察玩家, 一個玩家能被這個觀察員觀察到當且僅當該玩家在第Wj秒也正好
註意: 我們認為一個玩家到達自己的終點後該玩家就會結束遊戲, 他不能等待一 段時 間後再被觀察員觀察到。 即對於把結點J作為終點的玩家: 若他在第Wj秒重到達終點,則在結點J的觀察員不能觀察 到該玩家;若他正好在第Wj秒到達終點,則在結點的觀察員可以觀察到這個玩家。
輸入格式
第一行有兩個整數N和M 。其中N代表樹的結點數量, 同時也是觀察員的數量, M代表玩家的數量。
接下來n-1 行每行兩個整數U和V ,表示結點U 到結點V 有一條邊。
接下來一行N 個整數,其中第個整數為Wj , 表示結點出現觀察員的時間。
接下來 M行,每行兩個整數Si和Ti,表示一個玩家的起點和終點。
對於所有的數據,保證 。1<=Si,Ti<=N,0<=Wj<=N
輸出格式
輸出1行N 個整數,第j個整數表示結點j的觀察員可以觀察到多少人。
解題思路:
方法一:線段樹+樹鏈剖分
首先,我們考慮什麽樣的玩家可以被看到,那麽就是說什麽時候玩家到某個節點。
設玩家初始時的位置深度為d。
大概是這樣的,如果玩家在向上走時,會在0時刻走到路徑上d深度的點,在1時刻走到d-1深度的點,2時刻走到d-2是深度的點。
那麽在向上走的過程中,所經過點上的觀察員只要使等式(w+deep)=d成立,就能看見玩家。
同樣的在玩家向下走的時候也有類似的結論,就是只要玩家的(d-2*路徑上lca的deep)=(w-deep)就能看見。
那麽我們開線段樹存就好了。
對於每個深度開兩棵線段樹分別記錄向下走的和向上走的某個節點觀察的值,也就是說在每一個玩家的d上的線段樹對於每個玩家經歷的點上統一+1。
也就是說樹鏈上+1,這樣只要單點查詢就可以了。
樹鏈上+1,使用樹鏈剖分就好了^_^
線段樹占很大空間動態開點就好了
還有對於一些深度較淺的點我們發現最終的向下行走的索引可能為負,所以對於向下走的線段樹索引統一加上3e5
大概就是這樣了^_^
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int N=(int)(3e5); 6 const int T=(int)(13000000); 7 struct pnt{ 8 int w; 9 int hd; 10 int dp; 11 int fa; 12 int wgt; 13 int mxs; 14 int ind; 15 int top; 16 }p[N]; 17 struct ent{ 18 int twd; 19 int lst; 20 }e[N*2]; 21 struct sgt{ 22 int ls; 23 int rs; 24 int vls; 25 }tr[T]; 26 int cnt; 27 int siz; 28 int dnt; 29 int n,m; 30 int rtu[N*2],rtd[N*2]; 31 int sta[N],fin[N]; 32 void ade(int f,int t) 33 { 34 cnt++; 35 e[cnt].twd=t; 36 e[cnt].lst=p[f].hd; 37 p[f].hd=cnt; 38 } 39 void Tr_pushdown(int spc) 40 { 41 if(tr[spc].ls) 42 tr[tr[spc].ls].vls+=tr[spc].vls; 43 if(tr[spc].rs) 44 tr[tr[spc].rs].vls+=tr[spc].vls; 45 tr[spc].vls=0; 46 } 47 void Tr_build(int &spc,int l,int r,int plc) 48 { 49 if(!spc) 50 spc=++siz; 51 if(l==r) 52 return ; 53 int mid=(l+r)/2; 54 if(plc<=mid) 55 Tr_build(tr[spc].ls,l,mid,plc); 56 else 57 Tr_build(tr[spc].rs,mid+1,r,plc); 58 } 59 60 void Tr_add(int ll,int rr,int l,int r,int spc,int v) 61 { 62 if(!spc) 63 return ; 64 if(ll>r||l>rr) 65 return ; 66 if(ll<=l&&rr>=r) 67 { 68 tr[spc].vls+=v; 69 return ; 70 } 71 int mid=(l+r)/2; 72 Tr_add(ll,rr,l,mid,tr[spc].ls,v); 73 Tr_add(ll,rr,mid+1,r,tr[spc].rs,v); 74 return ; 75 } 76 int Tr_val(int plc,int spc,int l,int r) 77 { 78 if(!spc) 79 return 0; 80 if(l==r) 81 return tr[spc].vls; 82 Tr_pushdown(spc); 83 int mid=(l+r)/2; 84 if(plc<=mid) 85 return Tr_val(plc,tr[spc].ls,l,mid); 86 else 87 return Tr_val(plc,tr[spc].rs,mid+1,r); 88 } 89 void Basic_dfs(int x,int f) 90 { 91 p[x].fa=f; 92 p[x].dp=p[f].dp+1; 93 p[x].wgt=1; 94 int maxs=0; 95 for(int i=p[x].hd;i;i=e[i].lst) 96 { 97 int to=e[i].twd; 98 if(to==f) 99 continue; 100 Basic_dfs(to,x); 101 p[x].wgt+=p[to].wgt; 102 if(maxs<p[to].wgt) 103 { 104 maxs=p[to].wgt; 105 p[x].mxs=to; 106 } 107 } 108 } 109 void Build_dfs(int x,int tp) 110 { 111 if(!x) 112 return ; 113 p[x].ind=++dnt; 114 p[x].top=tp; 115 Tr_build(rtu[p[x].dp+p[x].w],1,n,dnt); 116 Tr_build(rtd[p[x].w-p[x].dp+N],1,n,dnt); 117 Build_dfs(p[x].mxs,tp); 118 for(int i=p[x].hd;i;i=e[i].lst) 119 { 120 int to=e[i].twd; 121 if(p[to].ind) 122 continue; 123 Build_dfs(to,to); 124 } 125 } 126 int LCA(int x,int y) 127 { 128 while(p[x].top!=p[y].top) 129 { 130 if(p[p[x].top].dp<p[p[y].top].dp) 131 swap(x,y); 132 x=p[p[x].top].fa; 133 } 134 if(p[x].dp>p[y].dp) 135 swap(x,y); 136 return x; 137 } 138 int main() 139 { 140 scanf("%d%d",&n,&m); 141 for(int i=1;i<n;i++) 142 { 143 int x,y; 144 scanf("%d%d",&x,&y); 145 ade(x,y); 146 ade(y,x); 147 } 148 for(int i=1;i<=n;i++) 149 scanf("%d",&p[i].w); 150 for(int i=1;i<=m;i++) 151 scanf("%d%d",&sta[i],&fin[i]); 152 Basic_dfs(1,1); 153 Build_dfs(1,1); 154 for(int i=1;i<=m;i++) 155 { 156 int f=LCA(sta[i],fin[i]); 157 int x=sta[i]; 158 int rt=p[sta[i]].dp; 159 while(p[x].top!=p[f].top) 160 { 161 Tr_add(p[p[x].top].ind,p[x].ind,1,n,rtu[rt],1); 162 x=p[p[x].top].fa; 163 } 164 Tr_add(p[f].ind,p[x].ind,1,n,rtu[rt],1); 165 Tr_add(p[f].ind,p[f].ind,1,n,rtu[rt],-1); 166 x=fin[i]; 167 rt=N+p[sta[i]].dp-2*p[f].dp; 168 while(p[x].top!=p[f].top) 169 { 170 Tr_add(p[p[x].top].ind,p[x].ind,1,n,rtd[rt],1); 171 x=p[p[x].top].fa; 172 } 173 Tr_add(p[f].ind,p[x].ind,1,n,rtd[rt],1); 174 } 175 for(int i=1;i<=n;i++) 176 { 177 int dowsid=Tr_val(p[i].ind,rtd[N+p[i].w-p[i].dp],1,n); 178 int upsid=Tr_val(p[i].ind,rtu[p[i].dp+p[i].w],1,n); 179 printf("%d ",dowsid+upsid); 180 } 181 return 0; 182 }
NOIP2016 天天愛跑步(線段樹/桶)