小C同学认为跑步非常有趣,于是决定制作一款叫做《天天爱跑步》的游戏。《天天爱跑步》是一个养成类游戏,需要玩家每天按时上线,完成打卡任务。
这个游戏的地图可以看作一棵包含 n 个结点和 n−1 条边的树,每条边连接两个结点,且任意两个结点存在一条路径互相可达。树上结点编号为从 1 到 n 的连续正整数。
现在有 m 个玩家,第 i 个玩家的起点为 Si,终点为 Ti。每天打卡任务开始时,所有玩家在第 0 秒同时从自己的起点出发,以每秒跑一条边的速度,不间断地沿着最短路径向着自己的终点跑去,跑到终点后该玩家就算完成了打卡任务。(由于地图是一棵树,所以每个人的路径是唯一的)
小C想知道游戏的活跃度,所以在每个结点上都放置了一个观察员。在结点 jj 的观察员会选择在第 Wj 秒观察玩家,一个玩家能被这个观察员观察到当且仅当该玩家在第 Wj 秒也正好到达了结点 j。小C想知道每个观察员会观察到多少人?
注意:我们认为一个玩家到达自己的终点后该玩家就会结束游戏,他不能等待一段时间后再被观察员观察到。即对于把结点 j 作为终点的玩家:若他在第 Wj 秒前到达终点,则在结点 j 的观察员不能观察到该玩家;若他正好在第 Wj 秒到达终点,则在结点 jj 的观察员可以观察到这个玩家。
输入格式
从标准输入读入数据。
第一行有两个整数 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 的观察员可以观察到多少人。
样例一
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 有边,……,n−1 与 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;
}