UOJ #261. 【NOIP2016】天天爱跑步
小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; }