版权声明:本文为博主原创文章,可以转载但是必须声明版权。 https://blog.csdn.net/forever_shi/article/details/82841420
题意好像不是很容易说明白,自己看题目吧。
题解:
如今再做往年NOIP题目还是不怎么会啊。这题想了想没想出来,然后看了好多题解,又对着y_immortal大神的代码研究了好久,才有些明白,水平还是不行啊。
首先我们把无根树转化为以1为根的有根树,dfs一边求出每个点的深度和他的倍增父节点数组。我们把一条路径看成两部分,一部分是向起点与终点的LCA走的,一部分是向下走的。我们发现,对于向上走的那一部分,在x这个点能看到的点应该满足
,而向下走的情况如果想在x被看到应该满足
,其中i为x子树中的节点。我们用一个桶来存
,然后对于每个点算它子树内
和
的数量,求法是减去进入子树之前的数量,然后加上遍历完子树之后的数量,就是子树的答案了。要特判路径一段是两个端点的LCA的情况,因为LCA会被重复计算。向上和向下的式子不太一样,画个图就能推出来。可能讲得确实不太清楚,我自己有些地方也不是很明白。
#include <bits/stdc++.h>
using namespace std;
int n,m,f[300010][20],hed[600010],cnt,num[3000010],ans[600010];
vector<int> adds[300010],addx[300010],dels[300010],delx[300010];
int w[600010],dep[600010],vis[600010];
const int gg=600005;
struct node
{
int to,next;
}a[600010];
void add(int from,int to)
{
a[++cnt].to=to;
a[cnt].next=hed[from];
hed[from]=cnt;
}
void dfs(int x,int fa)
{
f[x][0]=fa;
for(int i=1;i<=19;++i)
f[x][i]=f[f[x][i-1]][i-1];
for(int i=hed[x];i;i=a[i].next)
{
int y=a[i].to;
if(y!=fa)
{
dep[y]=dep[x]+1;
dfs(y,x);
}
}
}
int lca(int x,int y)
{
if(dep[x]<dep[y])
swap(x,y);
for(int i=19;i>=0;--i)
{
if(dep[f[x][i]]>=dep[y])
x=f[x][i];
}
if(x==y)
return x;
for(int i=19;i>=0;--i)
{
if(f[x][i]!=f[y][i])
{
x=f[x][i];
y=f[y][i];
}
}
return f[x][0];
}
void querys(int x)
{
ans[x]-=num[dep[x]+w[x]+gg];
vis[x]=1;
for(int i=hed[x];i;i=a[i].next)
{
int y=a[i].to;
if(!vis[y])
querys(y);
}
for(int i=0;i<adds[x].size();++i)
num[adds[x][i]]++;
ans[x]+=num[dep[x]+w[x]+gg];
for(int i=0;i<dels[x].size();++i)
num[dels[x][i]]--;
}
void queryx(int x)
{
ans[x]-=num[dep[x]-w[x]+gg];
vis[x]=1;
for(int i=hed[x];i;i=a[i].next)
{
int y=a[i].to;
if(!vis[y])
queryx(y);
}
for(int i=0;i<addx[x].size();++i)
num[addx[x][i]]++;
ans[x]+=num[dep[x]-w[x]+gg];
for(int i=0;i<delx[x].size();++i)
num[delx[x][i]]--;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n-1;++i)
{
int x,y;;
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
for(int i=1;i<=n;++i)
scanf("%d",&w[i]);
dep[1]=1;
dfs(1,0);
for(int i=1;i<=m;++i)
{
int s,t,l;
scanf("%d%d",&s,&t);
l=lca(s,t);
if(l==s)
{
addx[t].push_back(dep[s]+gg);
delx[s].push_back(dep[s]+gg);
}
else if(l==t)
{
adds[s].push_back(dep[s]+gg);
dels[t].push_back(dep[s]+gg);
}
else
{
addx[t].push_back(2*dep[l]-dep[s]+gg);
delx[l].push_back(2*dep[l]-dep[s]+gg);
adds[s].push_back(dep[s]+gg);
dels[l].push_back(dep[s]+gg);
if(dep[s]-dep[l]==w[l])
ans[l]--;
}
}
querys(1);
memset(vis,0,sizeof(vis));
queryx(1);
for(int i=1;i<=n;++i)
printf("%d ",ans[i]);
printf("\n");
return 0;
}