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