NOIP2016 天天爱跑步(线段树/桶)

题目描述

小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 }

 

转载于:https://www.cnblogs.com/blog-Dr-J/p/9508956.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值