1. 程式人生 > >NOIP2016 天天愛跑步(線段樹/桶)

NOIP2016 天天愛跑步(線段樹/桶)

短路徑 就會 遊戲 結束 else 決定 for class 正整數

題目描述

小c同學認為跑步非常有趣,於是決定制作一款叫做《天天愛跑步》的遊戲。天天愛跑步是一個養成類遊戲,需要 玩家每天按時上線,完成打卡任務。

這個遊戲的地圖可以看作一一棵包含 N個結點和N-1 條邊的樹, 每條邊連接兩個結點,且任意兩個結點存在一條路徑互相可達。樹上結點編號為從1到N的連續正整數。

現在有個玩家,第個玩家的 起點為Si ,終點為Ti 。每天打卡任務開始時,所有玩家在第0秒同時從自己的起點出發, 以每秒跑一條邊的速度, 不間斷地沿著最短路徑向著自己的終點跑去, 跑到終點後該玩家就算完成了打卡任務。 (由於地圖是一棵樹, 所以 每個人的路徑是唯一的)

小C想知道遊戲的活躍度, 所以在每個結點上都放置了一個觀察員。 在結點的觀察員會選 擇在第Wj秒觀察玩家, 一個玩家能被這個觀察員觀察到當且僅當該玩家在第Wj秒也正好

到達了結點J 。 小C想知道 每個觀察員會觀察到多少人?

註意: 我們認為一個玩家到達自己的終點後該玩家就會結束遊戲, 他不能等待一 段時 間後再被觀察員觀察到。 即對於把結點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 天天愛跑步(線段樹/桶)