[NOIP2016]天天爱跑步

       [NOIP2016]天天爱跑步

            输入文件:runninga.in   输出文件:runninga.out   简单对比
                时间限制:2 s   内存限制:512 MB

【题目描述】

 

小C同学认为跑步非常有趣,于是决定制作一款叫做《天天爱跑步》的游戏。《天天爱跑步》是一个养成类游戏,需要玩家每天按时上线,完成打卡任务。

   这个游戏的地图可以看作一棵包含n个结点和n-1条边的树,每条边连接两个结点,且任意两个结点存在一条路径互相可达。树上结点编号为从1到n的连续正整数。

   现在有m个玩家,第i个玩家的起点为Si,终点为Ti。每天打卡任务开始时,所有玩家在第0秒同时从自己的起点出发,以每秒跑一条边的速度,不间断地沿着最短路径向着自己的终点跑去,跑到终点后该玩家就算完成了打卡任务。(由于地图是一棵树,所以每个人的路径是唯一的)

    小C想知道游戏的活跃度, 所以在每个结点上都放置了一个观察员。 在结点的观察员会选择在第Wj秒观察玩家, 一个玩家能被这个观察员观察到当且仅当该玩家在第Wj秒也理到达了结点J  。 小C想知道每个观察员会观察到多少人?

    注意: 我们认为一个玩家到达自己的终点后该玩家就会结束游戏, 他不能等待一 段时间后再被观察员观察到。 即对于把结点J作为终点的玩家: 若他在第Wj秒前到达终点,则在结点J的观察员不能观察到该玩家;若他正好在第Wj秒到达终点,则在结点的观察员可以观察到这个玩家。

 

【输入格式】

 

第一行有两个整数n和m。其中n代表树的结点数量,同时也是观察员的数量,m代表玩家的数量。

接下来n-1行每行两个整数u和v,表示结点u到结点v有一条边。

接下来一行n个整数,其中第j个整数为Wj,表示结点j出现观察员的时间。

接下来m行,每行两个整数Si和Ti,表示一个玩家的起点和终点。

对于所有的数据,保证1≤Si,Ti≤n,0≤ Wj ≤n。

 

【输出格式】

输出1行n个整数,第j个整数表示结点j的观察员可以观察到多少人。

【样例1输入】

6 3
2 3
1 2
1 4
4 5
4 6
0 2 5 1 2 3
1 5
1 3
2 6

【样例1输出】

2 0 0 1 1 1

【样例2输入】

 

5 3

1 2

2 3

2 4

1 5

0 1 0 3 0

3 1

1 4

5 5

 

【样例2输出】

1 2 1 0 1

【提示】

 

对于1号点,W1=0,故只有起点为1号点的玩家才会被观察到,所以玩家1和玩家2被观察到,共2人被观察到。

   对于2号点,没有玩家在第2秒时在此结点,共0人被观察到。

   对于3号点,没有玩家在第5秒时在此结点,共0人被观察到。

   对于4号点,玩家1被观察到,共1人被观察到。

   对于5号点,玩家2被观察到,共1人被观察到。

   对于6号点,玩家3被观察到,共1人被观察到。

 

 

Solution:

  终于把这个坑填上了,强行安利一发大佬(好基友)的题解,真的写的很详细。

    http://blog.csdn.net/tworsto_dk/article/details/77175443

 

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #include <iostream>
 5 using namespace std;
 6 #define N 300010
 7 #define mid (l+r>>1)
 8 int read() {
 9     int s=0,f=1;
10     char ch=getchar();
11     for( ; ch<'0'||ch>'9'; f=(ch=='-')?-1:f,ch=getchar()) ;
12     for( ; ch>='0'&&ch<='9'; s=s*10+(ch^48),ch=getchar()) ;
13     return s*f;
14 }
15 int n,m,S[N],T[N],LCA[N],First[N],Last[N],p[N][31],tot,r[N],cnt;
16 int sum[N*21],ls[N*21],rs[N*21],root[N*21],deep[N],tim,Time[N],Ans[N];
17 struct EDGE{int to,next;}c[N<<1];
18 void add(int x,int y) {c[++tot]=(EDGE){y,r[x]};r[x]=tot;}
19 void dfs(int u,int f) {
20     First[u]=++tim;
21     for(int i=r[u]; ~i; i=c[i].next) {
22         if(c[i].to!=f) {
23             p[c[i].to][0]=u,deep[c[i].to]=deep[u]+1;
24             dfs(c[i].to,u);
25         }
26     } Last[u]=tim;
27 }
28 int lca(int x,int y) {
29     if(deep[x]<deep[y]) swap(x,y);
30     for(int j=20; j>=0; --j) if(deep[x]-(1<<j)>=deep[y]) x=p[x][j];
31     if(x==y) return x;
32     for(int j=20; j>=0; --j) if(p[x][j]!=-1&&p[x][j]!=p[y][j]) x=p[x][j],y=p[y][j];
33     return p[x][0];
34 }
35 void update(int &rt,int pos,int l,int r,int val) {
36     if(!rt) rt=++cnt;
37     if(!pos) return ;
38     sum[rt]+=val;
39     if(l==r) return ;
40     if(pos<=mid) update(ls[rt],pos,l,mid,val);
41     else update(rs[rt],pos,mid+1,r,val);
42 }
43 int query(int rt,int L,int R,int l,int r) {
44     if(!rt) return 0;
45     if(L<=l&&r<=R) return sum[rt];
46     int ans=0;
47     if(L<=mid) ans+=query(ls[rt],L,R,l,mid);
48     if(mid<R) ans+=query(rs[rt],L,R,mid+1,r);
49     return ans;
50 }
51 void clear() {
52     cnt=0;
53     memset(sum,0,sizeof(sum));
54     memset(root,0,sizeof(root));
55     memset(ls,0,sizeof(ls));
56     memset(rs,0,sizeof(rs));
57 }
58 int main() {
59     freopen("runninga.in","r",stdin);
60     freopen("runninga.out","w",stdout);
61     n=read(),m=read();
62     memset(r,0xff,sizeof(r));
63     memset(p,0xff,sizeof(p));
64     for(int x,y,i=1; i<n; ++i) x=read(),y=read(),add(x,y),add(y,x);    
65     deep[1]=1; dfs(1,1); 
66     for(int j=1; (1<<j)<=n; ++j) for(int i=1; i<=n; ++i) if(p[i][j-1]!=-1) p[i][j]=p[p[i][j-1]][j-1];
67     for(int i=1; i<=n; ++i) Time[i]=read();
68     for(int i=1; i<=m; ++i) S[i]=read(),T[i]=read(),LCA[i]=lca(S[i],T[i]);
69     for(int i=1; i<=m; ++i) {
70         update(root[deep[S[i]]],First[S[i]],1,n,1);
71         update(root[deep[S[i]]],First[p[LCA[i]][0]],1,n,-1);
72     } for(int i=1; i<=n; ++i) Ans[i]+=query(root[deep[i]+Time[i]],First[i],Last[i],1,n);
73     clear();
74     for(int i=1; i<=m; ++i) {
75         int D=deep[S[i]]-(deep[LCA[i]]<<1)+(n<<1);
76         update(root[D],First[T[i]],1,n,1);
77         update(root[D],First[LCA[i]],1,n,-1);
78     } for(int i=1; i<=n; ++i) Ans[i]+=query(root[Time[i]-deep[i]+(n<<1)],First[i],Last[i],1,n);
79     for(int i=1; i<=n; ++i) printf("%d ",Ans[i]);
80     return 0;
81 }

 

posted @ 2017-11-08 06:19  Forever_goodboy  阅读(322)  评论(0编辑  收藏  举报