• UOJ #261. 【NOIP2016】天天爱跑步


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

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

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

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

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

    输入格式

    从标准输入读入数据。

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

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

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

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

    对于所有的数据,保证 1Si,Tin0Wjn

    输出格式

    输出到标准输出。

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

    样例一

    input

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

    output

    2 0 0 1 1 1
    
    

    explanation

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

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

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

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

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

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

    样例二

    input

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

    output

    1 2 1 0 1
    
    

    限制与约定

    每个测试点的数据规模及特点如下表所示。提示:数据范围的个位上的数字可以帮助判断是哪一种数据类型。

    测试点编号n
    m约定
    1 =991 =991 所有人的起点等于自己的终点,即 Si=Ti
    2
    3 =992 =992 Wj=0
    4
    5 =993 =993
    6 =99994 =99994 树退化成一条链,其中 1 与 2 有边,2 与 3 有边,…,n1 与 n 有边
    7
    8
    9 =99995 =99995 所有的 Si=1
    10
    11
    12
    13 =99996 =99996 所有的 Ti=1
    14
    15
    16
    17 =99997 =99997
    18
    19
    20 =299998 =299998

    时间限制:2s

    空间限制:512MB

    下载

    样例数据下载

    题目连接:http://uoj.ac/problem/261

    解题报告:

    从一开始自己YY玄学做法(在线处理,复杂度O(kmlogn),k特别玄学,期望值为4~5,可能会退化成n),到卡常数,到fread()和动态开空间(吐血).

    最后还是认认真真看题解,写正解(离线处理,复杂度O(mlogn+n)).

    树上差分+桶维护.

    先将一条路径(s,t)拆成向上(s,lca)和向下(lca,t)的两条路径,

    对于向上路径,路径的点x满足dep[x]+w[x]=dep[s],则可以被观察到,在s点把dep[s]放入对应桶中,lca处取出.

    同理对于向下的路径,在t点把2*dep[l]-dep[s]放入桶中,lca处取出.

    dfs统计差分和.

    玄学做法

    #include<cstdio>
    #include<iostream>
    #include<vector>
    #include<algorithm>
    #include<cmath>
    #define BIG 600005
    #define ll long long
    #define FOR(i,s,t) for(register int i=s;i<=t;++i)
    using namespace std;
    const int N=BIG>>1;
    int nxt[BIG],to[BIG],las[N],w[N],ans[N],
    	sz[N],dep[N],f[N],top[N],xu[BIG],sign[BIG];
    vector<int>v1[BIG],v2[BIG];
    int n,m,x,y,dfn,l,t,need,tot;
    inline void read(int &x){
    	char c;
    	while(c=getchar(),c>'9'||c<'0');
    	x=c-48;
    	while(c=getchar(),c>='0'&&c<='9')x=(x<<1)+(x<<3)+c-48;
    	return ;
    }
    inline void add(int x,int y){
    	nxt[++tot]=las[x];
    	las[x]=tot;
    	to[tot]=y;
    	return;
    }
    inline void dfs1(int now){
    	sz[now]=1;
    	for(register int e=las[now];e;e=nxt[e])
    		if(!dep[to[e]]){
    			dep[to[e]]=dep[now]+1;
    			f[to[e]]=now;
    			dfs1(to[e]);
    			sz[now]+=sz[to[e]];
    		}
    	return;
    }
    inline void dfs2(int now,int chain){
    	top[now]=chain;
    	xu[now]=++dfn;
    	register int i=0;
    	for(register int e=las[now];e;e=nxt[e])
    		if(sz[to[e]]>sz[i]&&to[e]!=f[now])
    			i=to[e];
    	if(!i)
    		return;
    	dfs2(i,chain);
    	for(register int e=las[now];e;e=nxt[e])
    		if(to[e]!=f[now]&&to[e]!=i)
    			dfs2(to[e],to[e]);
    	return;
    } 
    inline int lca(int x,int y){
    	for(;top[x]!=top[y];dep[top[x]]>dep[top[y]]?x=f[top[x]]:y=f[top[y]]);
    	return dep[x]<dep[y]?x:y;
    }
    inline void find(int goal,int x,int l){
    	if(xu[goal]<xu[l]||xu[goal]>xu[x]||dep[goal]>dep[x])
    		return; 	 
    	for(;top[x]!=top[l];){
    		if(xu[top[x]]<=xu[goal]&&xu[goal]<=xu[x]){
    			++ans[goal];
    			return;
    		}
    		x=f[top[x]];
    	}
    	if(xu[l]<=xu[goal]&&xu[goal]<=xu[x])
    		++ans[goal];
    	return;
    }
    inline void dfs3(int now){
    	for(register int e=las[now];e;e=nxt[e])
    		if(to[e]!=f[now]){
    			dfs3(to[e]);
    			sign[now]+=sign[to[e]];
    		}
    	return;
    }
    int wr[51];
    inline void write(int x){
    	if(!x)
    		putchar(48);
    	else{
    		while(x)
    			wr[++wr[0]]=x%10,x/=10;
    		while(wr[0])
    			putchar(48+wr[wr[0]--]); 
    	}
    	putchar(' ');
    }
    int main(){
        read(n);
        read(m);
        FOR(i,2,n){
        	read(x);
        	read(y);
        	add(x,y);
        	add(y,x);
    	}
    	FOR(i,1,n)
    		read(w[i]);
    	dep[1]=1;
    	dfs1(1);
    	dfs2(1,1);
    	if(n==99995){
    		while(m--){
    			read(x);
    			read(y);
    			++sign[y];
    		}
    		dfs3(1);
    		FOR(i,1,n)
    			if(w[i]==dep[i]-1)
    				printf("%d ",sign[i]);
    			else
    				printf("0 ");
    		return 0;
    	}
    	FOR(i,1,n){
    		v1[dep[i]-w[i]+N].push_back(i);
    		v2[w[i]+dep[i]].push_back(i);
    	}
    	while(m--){
    		read(x);
    		read(y);
    		l=lca(x,y);
    		t=dep[x]-dep[l];
    		need=dep[l]-t+N;
    		for(register int i=0;i<v1[need].size();++i)
    			find(v1[need][i],y,l);
    		need=dep[l]+t;
    		for(register int i=0;i<v2[need].size();++i)
    			find(v2[need][i],x,l);
    		if(w[l]==t)
    			--ans[l];
    	}
    	FOR(i,1,n)
    		write(ans[i]);
        return 0;
    }
    

      

    卡常数

    #include<cstdio>
    #include<iostream>
    #include<vector>
    #include<algorithm>
    #define BIG 600005
    #define ll long long
    #define FOR(i,s,t) for(register int i=s;i<=t;++i)
    const int N=BIG>>1;
    int nxt[BIG],to[BIG],las[N],w[N],ans[N],
    	sz[N],dep[N],f[N],top[N],xu[BIG],sign[BIG];
    std::vector<int>v1[BIG],v2[BIG];
    int n,m,x,y,dfn,l,t,need,tot,goal;
    char *ch;
    inline void read(int &x){
    	x=0; while (*ch<'0'||*ch>'9') ++ch;
    	while (*ch>='0'&&*ch<='9') {
    		x=(x<<1)+(x<<3)+*ch-48;
    		++ch;
    	}
    }
    inline void add(int x,int y){
    	nxt[++tot]=las[x];
    	las[x]=tot;
    	to[tot]=y;
    	return;
    }
    inline void dfs1(int now){
    	sz[now]=1;
    	for(register int e=las[now];e;e=nxt[e])
    		if(!dep[to[e]]){
    			dep[to[e]]=dep[now]+1;
    			f[to[e]]=now;
    			dfs1(to[e]);
    			sz[now]+=sz[to[e]];
    		}
    	return;
    }
    inline void dfs2(int now,int chain){
    	top[now]=chain;
    	xu[now]=++dfn;
    	register int i=0;
    	for(register int e=las[now];e;e=nxt[e])
    		if(sz[to[e]]>sz[i]&&to[e]!=f[now])
    			i=to[e];
    	if(!i)
    		return;
    	dfs2(i,chain);
    	for(register int e=las[now];e;e=nxt[e])
    		if(to[e]!=f[now]&&to[e]!=i)
    			dfs2(to[e],to[e]);
    	return;
    } 
    inline int lca(int x,int y){
    	for(;top[x]!=top[y];dep[top[x]]>dep[top[y]]?x=f[top[x]]:y=f[top[y]]);
    	return dep[x]<dep[y]?x:y;
    }
    inline void find(int goal,int x,int l){	 
    	for(;top[x]!=top[l];){
    		if(xu[top[x]]<=xu[goal]&&xu[goal]<=xu[x]){
    			++ans[goal];
    			return;
    		}
    		x=f[top[x]];
    	}
    	if(xu[l]<=xu[goal]&&xu[goal]<=xu[x])
    		++ans[goal];
    	return;
    }
    inline void dfs3(int now){
    	for(register int e=las[now];e;e=nxt[e])
    		if(to[e]!=f[now]){
    			dfs3(to[e]);
    			sign[now]+=sign[to[e]];
    		}
    	return;
    }
    int wr[51];
    inline void write(int x){
    	if(!x)
    		putchar(48);
    	else{
    		while(x)
    			wr[++wr[0]]=x%10,x/=10;
    		while(wr[0])
    			putchar(48+wr[wr[0]--]); 
    	}
    	putchar(' ');
    }
    inline bool cmp(int a,int b){
    	return xu[a]<xu[b];
    }
    int main(){
    	fseek(stdin,0l,SEEK_END);
    	int flen=ftell(stdin);
    	fseek(stdin,0l,SEEK_SET);
    	char *buffer = new char [flen+1];
    	fread(buffer,1,flen,stdin);
    	ch=buffer;
    	
        read(n);
        read(m);
        for(register int i=2;i<=n;++i){
        	read(x);
        	read(y);
        	add(x,y);
        	add(y,x);
    	}
    	for(register int i=1;i<=n;++i)
    		read(w[i]);
    	dep[1]=1;
    	dfs1(1);
    	dfs2(1,1);
    	if(n==99995){
    		while(m--){
    			read(x);
    			read(y);
    			++sign[y];
    		}
    		dfs3(1);
    		FOR(i,1,n)
    			if(w[i]==dep[i]-1)
    				printf("%d ",sign[i]);
    			else
    				printf("0 ");
    		return 0;
    	}
    	for(register int i=1;i<=n;++i){
    		v1[dep[i]-w[i]+N].push_back(i);
    		v2[w[i]+dep[i]].push_back(i);
    	}
    	for(register int i=0;i<=(N<<1)-3;++i){
    		std::sort(v1[i].begin(),v1[i].end(),cmp);	
    		std::sort(v2[i].begin(),v2[i].end(),cmp);
    	}
    	while(m--){
    		read(x);
    		read(y);
    		l=lca(x,y);
    		t=dep[x]-dep[l];
    		need=dep[l]-t+N;
    		for(register int i=0;i<v1[need].size();++i){
    			goal=v1[need][i];
    			if(xu[goal]>=xu[l]&&xu[goal]<=xu[y])
    				find(goal,y,l);
    			if(xu[goal]>xu[y])
    				break;
    		}
    		need=dep[l]+t;
    		for(register int i=0;i<v2[need].size();++i){
    			goal=v2[need][i];
    			if(xu[goal]>=xu[l]&&xu[goal]<=xu[x])
    				find(goal,x,l);
    			if(xu[goal]>xu[x])
    				break;
    		}
    		if(w[l]==t)
    			--ans[l];
    	}
    	FOR(i,1,n)
    		write(ans[i]);
        return 0;
    }
    

      

    正解

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<vector>
    using namespace std;
    char temp[1<<24],*S=temp;
    inline int read(){
    	int data=0;char c=*S++;
    	while(c>'9'||c<'0')c=*S++;
    	while(c>='0'&&c<='9')data=(data<<1)+(data<<3)+c-'0',c=*S++;
    	return data;
    }
    #define M 600010
    #define N (M>>1)
    #define ll long long
    #define FOR(s,t) for(register int i=s;i<=t;++i)
    #define VIS(now) for(register int e=las[now];e;e=nxt[e])
    #define FR(s,t) for(register int i=s;i<t;++i)
    #define fin freopen("test.in","r",stdin);
    #define fout freopen("test.out","w",stdout);
    int n,m,tot=1,t;
    int nxt[M],las[N],to[M],w[N];
    inline void add(int x,int y){
    	nxt[++tot]=las[x];las[x]=tot;to[tot]=y;
    }
    namespace TCP{
    	int dep[N],f[N],sz[N],top[N];
    	inline void dfs1(int now){
    		sz[now]=1;
    		VIS(now)if(!dep[to[e]])
    			dep[to[e]]=dep[now]+1,f[to[e]]=now,dfs1(to[e]),sz[now]+=sz[to[e]];
    	}
    	inline void dfs2(int now,int chain){
    		top[now]=chain;
    		register int i=0;
    		VIS(now)if(to[e]!=f[now]&&sz[i]<sz[to[e]])i=to[e];
    		if(!i)return;
    		dfs2(i,chain);
    		VIS(now)if(to[e]!=f[now]&&to[e]!=i)dfs2(to[e],to[e]);
    	}
    	inline int lca(int x,int y){
    		for(;top[x]!=top[y];dep[top[x]]>dep[top[y]]?x=f[top[x]]:y=f[top[y]]);
    		return dep[x]<dep[y]?x:y;
    	}
    };
    using namespace TCP;
    vector<int>qs[M<<1],qt[M<<1];
    int x,y,l;
    int ans[N],t1[M<<1],t2[M<<1];
    inline void dfs3(int now){	
    	int a=t1[dep[now]+w[now]];
    	VIS(now)if(to[e]!=f[now])dfs3(to[e]);
    	FR(0,qs[now].size())qs[now][i]>0?++t1[qs[now][i]]:--t1[-qs[now][i]];
    	ans[now]+=t1[dep[now]+w[now]]-a;
    }
    inline void dfs4(int now){
    	int a=t2[dep[now]-w[now]+N];
    	VIS(now)if(to[e]!=f[now])dfs4(to[e]);
    	FR(0,qt[now].size())qt[now][i]>0?++t2[qt[now][i]]:--t2[-qt[now][i]];
    	ans[now]+=t2[dep[now]-w[now]+N]-a;
    }
    int main(){
    	//fin;fout;
    	fread(temp,1,1<<24,stdin);
    	n=read(),m=read();
    	FOR(2,n)x=read(),y=read(),add(x,y),add(y,x);
    	FOR(1,n)w[i]=read();
    	dep[1]=1;dfs1(1);dfs2(1,1);
    	while(m--){
    		x=read(),y=read();
    		l=lca(x,y);
    		qs[x].push_back(dep[x]);qs[l].push_back(-dep[x]);
    		qt[y].push_back(2*dep[l]-dep[x]+N);qt[l].push_back(dep[x]-2*dep[l]-N);
    		if(dep[l]+w[l]==dep[x])++ans[l];
    	}
    	dfs3(1);dfs4(1);
    	FOR(1,n)printf("%d ",ans[i]);
    	return 0;
    }
    

      

  • 相关阅读:
    SpringBoot集成Swagger2中不同环境开关配置
    mysql
    pip 命令汇总
    mysql 时间查询(当天、本周,本月,上一个月的数据)
    MYSQL 常用函数
    java8 array、list操作 汇【6】)- Java8 Lambda表达式增强版Comparator和排序
    解决pip安装超时的问题
    Java对象为空时,将null转换为"" 保存值为空的属性
    mysql -- 模糊查询的四种方法
    Mysql 查询以某个字符开头的语句
  • 原文地址:https://www.cnblogs.com/Stump/p/7748238.html
Copyright © 2020-2023  润新知