• [noip2016]天天爱跑步


    题目描述

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

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

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

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

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

    输入输出格式

    输入格式:

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

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

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

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

    对于所有的数据,保证1leq S_i,T_ileq n, 0leq W_jleq n 。

    输出格式:

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


    个人思路:

    • 类似"雨天的尾巴",在dfs的过程中合并数据即可。可以注意到W范围较大,且区间具有可合并性(非最大/小值等操作).
    • 因此,可利用vector维护每个点上"玩家"的增加/减少情况,再在dfs的过程中利用全局数组合并即可.
    • 具体地说,对于每个玩家,分成两段分别考虑,即S->LCA和LCA->T。可以发现,在第一种情况下满足W[x]-d[x]=d[s];在第二种情况下满足W[x]-d[x]=d[s]-2*d[lca(s,t)].
    • 代入树上差分的基本过程中可以发现:在第一种情况下,利用区间合并使得lca(s,t)与s之间的点可以利用该情况的数据,第二种情况同理。当然,也可以直接用两个局部变量cnt1,cnt2分别维护W[x]-d[x],W[x]+d[x],并在一次dfs中求得结果.

    #include<cstdio>
    #include<iostream>
    #include<vector>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int MAXN=1000010,MAXM=1000010;
    struct Edge{
    	int from,to,nxt;
    }e[MAXM];
    int head[MAXN],edgeCnt=1;
    void addEdge(int u,int v){
    	e[++edgeCnt].from=u;
    	e[edgeCnt].to=v;
    	e[edgeCnt].nxt=head[u];
    	head[u]=edgeCnt;
    }
    int dep[MAXN],f[MAXN][21];
    void dfs_Lca(int x){
    	dep[x]=dep[f[x][0]]+1;
    	for(int i=1;i<=20;i++){
    		f[x][i]=f[f[x][i-1]][i-1];
    	}
    	for(int i=head[x];i;i=e[i].nxt){
    		int v=e[i].to;
    		if(!dep[v]){
    			f[v][0]=x;
    			dfs_Lca(v);
    		}
    	}
    }
    int lca(int a,int b){
    	if(dep[a]>dep[b])swap(a,b);
    	for(int i=20;i>=0;i--){
    		if(dep[b]-(1<<i)>=dep[a])b=f[b][i];
    	}
    	if(a==b)return a;
    	for(int i=20;i>=0;i--)
    		if(f[a][i]!=f[b][i])
    			a=f[a][i],b=f[b][i];
    	return f[a][0];
    }
    
    int w[MAXN];
    struct player{
    	int s,t;
    }players[MAXN];
    struct item{
    	int pos,value;
    };
    vector<item> vecs_First[MAXN];
    int c[MAXN],ans[MAXN];
    void dfs_Solve_First(int x){
    	int cnt=c[w[x]+dep[x]];
    	for(int i=head[x];i;i=e[i].nxt){
    		int v=e[i].to;
    		if(v!=f[x][0]){
    			dfs_Solve_First(v);
    		}
    	}
    	while(!vecs_First[x].empty()){
    		item nowItem=vecs_First[x].back();vecs_First[x].pop_back();
    		int nowPos=nowItem.pos,nowValue=nowItem.value;
    		c[nowPos]+=nowValue;
    	}
    	ans[x]+=c[w[x]+dep[x]]-cnt;
    }
    void init(){
    	memset(c,0,sizeof(c));
    	
    }
    vector<item> vecs_Second[MAXN];
    void dfs_Solve_Second(int x){
    	int cnt=c[w[x]-dep[x]];
    	for(int i=head[x];i;i=e[i].nxt){
    		int v=e[i].to;
    		if(v!=f[x][0]){
    			dfs_Solve_Second(v);
    		}
    	}
    	while(!vecs_Second[x].empty()){
    		item nowItem=vecs_Second[x].back();vecs_Second[x].pop_back();
    		int nowPos=nowItem.pos,nowValue=nowItem.value;
    		c[nowPos]+=nowValue;
    	}
    	ans[x]+=c[w[x]-dep[x]]-cnt;
    }
    int main(){
    	int n,m;
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n-1;i++){
    		int u,v;
    		scanf("%d%d",&u,&v);
    		addEdge(u,v);
    		addEdge(v,u);
    	}
    	f[1][0]=0;
    	dfs_Lca(1);
    	
    	for(int i=1;i<=n;i++){
    		scanf("%d",&w[i]);
    	}
    	for(int i=1;i<=m;i++){
    		scanf("%d%d",&players[i].s,&players[i].t);
    		vecs_First[players[i].s].
    		push_back(item{dep[players[i].s],1});
    		vecs_First[f[lca(players[i].s,players[i].t)][0]].
    		push_back(item{dep[players[i].s],-1});
    		vecs_Second[players[i].t].
    		push_back(item{dep[players[i].s]-2*dep[lca(players[i].s,players[i].t)],1});
    		vecs_Second[lca(players[i].s,players[i].t)].
    		push_back(item{dep[players[i].s]-2*dep[lca(players[i].s,players[i].t)],-1});
    	}
    	dfs_Solve_First(1);
    	init();
    	dfs_Solve_Second(1);
    	for(int i=1;i<=n-1;i++){
    		cout<<ans[i]<<" ";
    	}
    	printf("%d
    ",ans[n]);
    	return 0;
    }
  • 相关阅读:
    内置系统账户:Local system/Network service/Local Service 区别
    python-基于文件导入的特性的单例模式
    php原因 nginx报错[error] 10773#0: *272212065 recv() failed (104: Connection reset by peer) while reading response header from upstream
    实用Django ORM实用操作方法
    session是什么和cookie的区别?
    Python可迭代对象,迭代器,生成器
    浅析python中的GIL锁和协程
    git 常用
    testlink安装
    redmine搭建
  • 原文地址:https://www.cnblogs.com/zbsy-wwx/p/11680633.html
Copyright © 2020-2023  润新知