题目描述
小c同学认为跑步非常有趣,于是决定制作一款叫做《天天爱跑步》的游戏。《天天爱跑步》是一个养成类游戏,需要玩家每天按时上线,完成打卡任务。
这个游戏的地图可以看作一一棵包含 nn 个结点和 n-1n−1 条边的树, 每条边连接两个结点,且任意两个结点存在一条路径互相可达。树上结点编号为从11 到nn 的连续正整数。
现在有mm 个玩家,第ii 个玩家的起点为 S_iSi ,终点为 T_iTi 。每天打卡任务开始时,所有玩家在第00 秒同时从自己的起点出发, 以每秒跑一条边的速度, 不间断地沿着最短路径向着自己的终点跑去, 跑到终点后该玩家就算完成了打卡任务。 (由于地图是一棵树, 所以每个人的路径是唯一的)
小C想知道游戏的活跃度, 所以在每个结点上都放置了一个观察员。 在结点jj 的观察员会选择在第W_jWj 秒观察玩家, 一个玩家能被这个观察员观察到当且仅当该玩家在第W_jWj 秒也理到达了结点 jj 。 小C想知道每个观察员会观察到多少人?
注意: 我们认为一个玩家到达自己的终点后该玩家就会结束游戏, 他不能等待一 段时间后再被观察员观察到。 即对于把结点jj 作为终点的玩家: 若他在第W_jWj 秒前到达终点,则在结点jj 的观察员不能观察到该玩家;若他正好在第W_jWj 秒到达终点,则在结点jj 的观察员可以观察到这个玩家。
输入输出格式
输入格式:第一行有两个整数nn 和mm 。其中nn 代表树的结点数量, 同时也是观察员的数量, mm 代表玩家的数量。
接下来 n- 1n−1 行每行两个整数uu 和 vv ,表示结点 uu 到结点 vv 有一条边。
接下来一行 nn 个整数,其中第jj 个整数为W_jWj , 表示结点jj 出现观察员的时间。
接下来 mm 行,每行两个整数S_iSi ,和T_iTi ,表示一个玩家的起点和终点。
对于所有的数据,保证1\leq S_i,T_i\leq n, 0\leq W_j\leq n1≤Si,Ti≤n,0≤Wj≤n 。
输出1行 nn 个整数,第jj 个整数表示结点jj 的观察员可以观察到多少人。
输入输出样例
6 3 2 3 1 2 1 4 4 5 4 6 0 2 5 1 2 3 1 5 1 3 2 6
2 0 0 1 1 1
说明
【样例1说明】
对于1号点,W_i=0Wi=0 ,故只有起点为1号点的玩家才会被观察到,所以玩家1和玩家2被观察到,共有2人被观察到。
对于2号点,没有玩家在第2秒时在此结点,共0人被观察到。
对于3号点,没有玩家在第5秒时在此结点,共0人被观察到。
对于4号点,玩家1被观察到,共1人被观察到。
对于5号点,玩家1被观察到,共1人被观察到。
对于6号点,玩家3被观察到,共1人被观察到。
【子任务】
每个测试点的数据规模及特点如下表所示。 提示: 数据范围的个位上的数字可以帮助判断是哪一种数据类型。
LCA+树上差分+桶。。。set[x] : 以x为LCA的路径的起点的集合。
num[x]: 以x为路径起点的路径条数。
set2[x]: 以x为终点的路径的起点集合。
set3[x]: 以x为LCA的路径的终点的集合。
正解并不是对一个个玩家进行操作。
而是先对全部玩家进行一些预处理,然后用两个类似的dfs函数对整棵树处理。
最后再做一些微调,就输出答案。
对于玩家在树上的路径(u,v)
我们可以对其进行拆分。
拆分成: u ---> LCA(u,v) 与 LCA(u,v) ---> v 两条路径。
对于这一步,因为我们在一开始已经说明是先对每个玩家进行预处理,LCA 我用了树链剖分
我们先考虑 u ---> LCA(u,v) 这条路径,这是一条向“上”跑的路径。
对与这条路径上的点i来说,当且仅当deep[i]+w[i] = deep[u]时,u节点对i节点是有贡献的。
那么也就是说,只要符合deep[i]+w[i]的全部是玩家起点的点,就能对i点产生贡献。
ans[i]加上的其实就是i的子树对i的贡献,因为我们在处理好子树之后的,我们已经处理好了对i有影响的节点,
所以我们只要加上先后之间的桶差值就相当于统计了答案。
其作用是删去桶中以i为LCA的路径的起点深度桶的值,因为当我们遍历完i节点的孩子时,
对于以i节点为LCA的路径来说,这条路径上的信息对i的祖先节点是不会有影响的。
所以要将其删去。
我们再来考虑向下的路径,即LCA(u,v) --->v。
对于向下走的路径,我们也思考,在什么条件下,这条路径上的点会获得贡献呢?
很明显的,当 dis(u,v)-deep[v] = w[i]-deep[i] 等式成立的时候,这条路径将会对i点有贡献。
对于桶bucket来说,我们在计算的过程中其下标可能是负值,所以我们在操作桶时要将其下标右移 n, 即点数。
·如果一条路径的LCA能观察到这条路上的人,我们还需将该LCA去重。
即: if(deep[u] == deep[lca]+w[i])ans[lca]--;
附上苦心敲出的炒鸡恶心的代码:
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<vector>
#define MAXN 300010
using namespace std;
vector<int> set1[MAXN],set2[MAXN],set3[MAXN];
int n,m,c=1,d=1;
int head[MAXN],deep[MAXN],son[MAXN],size[MAXN],fa[MAXN],id[MAXN],top[MAXN];
int w[MAXN],dis[MAXN],num[MAXN],ans[MAXN],devote[MAXN<<1];
bool vis[MAXN];
struct node1{
int next,to;
}a[MAXN<<1];
struct node2{
int s,t,lca,dis;
}b[MAXN];
inline int read(){
int date=0,w=1;char c=0;
while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
return date*w;
}
inline void add(int x,int y){
a[c].to=y;
a[c].next=head[x];
head[x]=c++;
a[c].to=x;
a[c].next=head[y];
head[y]=c++;
}
void dfs1(int rt){
son[rt]=0;size[rt]=1;
for(int i=head[rt];i;i=a[i].next){
int will=a[i].to;
if(!deep[will]){
deep[will]=deep[rt]+1;
dis[will]=dis[rt]+1;
fa[will]=rt;
dfs1(will);
size[rt]+=size[will];
if(size[son[rt]]<size[will])son[rt]=will;
}
}
}
void dfs2(int rt,int f){
id[rt]=d++;top[rt]=f;
if(son[rt])dfs2(son[rt],f);
for(int i=head[rt];i;i=a[i].next){
int will=a[i].to;
if(will!=fa[rt]&&will!=son[rt])
dfs2(will,will);
}
}
int LCA(int x,int y){
while(top[x]!=top[y]){
if(deep[top[x]]<deep[top[y]])swap(x,y);
x=fa[top[x]];
}
if(deep[x]>deep[y])swap(x,y);
return x;
}
void dfs3(int rt){
vis[rt]=true;
int x=devote[deep[rt]+w[rt]+n];
for(int i=head[rt];i;i=a[i].next){
int v=a[i].to;
if(!vis[v])dfs3(v);
}
devote[deep[rt]+n]+=num[rt];
ans[rt]+=devote[deep[rt]+w[rt]+n]-x;
int l=set1[rt].size();
for(int i=0;i<l;i++)devote[deep[set1[rt][i]]+n]--;
vis[rt]=false;
}
void dfs4(int rt){
vis[rt]=true;
int x=devote[w[rt]-deep[rt]+n];
for(int i=head[rt];i;i=a[i].next){
int v=a[i].to;
if(!vis[v])dfs4(v);
}
int l=set2[rt].size();
for(int i=0;i<l;i++)devote[set2[rt][i]+n]++;
ans[rt]+=devote[w[rt]-deep[rt]+n]-x;
l=set3[rt].size();
for(int i=0;i<l;i++)devote[set3[rt][i]+n]--;
vis[rt]=false;
}
void work(){
for(int i=1;i<=m;i++){
b[i].s=read();b[i].t=read();
b[i].lca=LCA(b[i].s,b[i].t);
b[i].dis=dis[b[i].s]+dis[b[i].t]-dis[b[i].lca]*2;
num[b[i].s]++;
set1[b[i].lca].push_back(b[i].s);
set2[b[i].t].push_back(b[i].dis-deep[b[i].t]);
set3[b[i].lca].push_back(b[i].dis-deep[b[i].t]);
}
dfs3(1);
dfs4(1);
for(int i=1;i<=m;i++)if(deep[b[i].s]==deep[b[i].lca]+w[b[i].lca])ans[b[i].lca]--;
for(int i=1;i<=n;i++)printf("%d ",ans[i]);
}
void init(){
int x,y;
n=read();m=read();
for(int i=1;i<n;i++){
x=read();y=read();
add(x,y);
}
for(int i=1;i<=n;i++){
w[i]=read();
ans[i]=0;
}
deep[1]=1;dis[1]=0;
dfs1(1);
dfs2(1,1);
}
int main(){
init();
work();
return 0;
}