题目:luogu1600.
题目大意:给定一棵树和树上每个节点的,现在给出m对和,表示从到会有一个人沿树上的路径走过,并且这个人每秒移动到下一个点.现在每个人都在时刻0走出,询问每一个点i,请你输出第时刻有多少人会在点i.
这道题真的是史上最难的NOIP题啊...
我们现在一步步分析部分分,一步步逼近正解.
部分分1:s=1.
若s=1,很容易发现一个人i会对点j做出贡献,仅当有一个祖先为j且.
我们可以记录一个计数数组cnt,也就是一个桶,当我们退出一个点k时,我们将加以k为终点的路径数量,并计算出答案.
部分分2:t=1.
若t=1,很容易发现一个人i会对点j做出贡献,仅当有一个祖先为j且.
我们将这个式子变式即可得到.
s=1类似的,记录一个计数数组cnt,当我们进入一个点k时,我们将加以k为起点的路径数量,并计算答案.
部分分3:链.
如果是链的话,那么我们可以发现一个人要么是一直往右走,要么是一直往左走.
那么我们将人分为两种,一种是往左走的,一种是往右走的.
然后我们依旧记录一个桶,往左走的我们从1开始递归,往右走的我们从n开始递归.
当我们往左走时,我们退出一个点时,我们将这个点的答案计算出来,然后将所有已它为终点的起点的贡献去掉,这样就能保证不对后面的答案产生影响,具体这个功能可以用vector实现.
AC做法.
AC做法其实就是链的数据做法的拓展.
我们只需要将一条路径分成两条链,一条从终点到lca,一条从起点到lca.
拆完链之后发现这是一个树上差分,不过要注意若LCA计入了两次,要去掉一次.
那么很容易就可以做了.
还有这道题其实是可以写dsu on tree和线段树合并的,思路就是因为有子树查询cnt数组,有兴趣的自己去写写吧,我放弃了.
代码如下:
#include<bits/stdc++.h>
using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=300000;
int n,m;
int s[N+9],t[N+9],w[N+9];
int lca[N+9],dis[N+9];
int cnt[3*N+9],ans[N+9],num[N+9];
vector<int>q1[N+9],q2[N+9],q3[N+9];
struct side{
int y,next;
}e[N*2+9];
int lin[N+9],top;
int deep[N+9],gr[N+9][20];
bool use[N+9];
void ins(int x,int y){
e[++top].y=y;
e[top].next=lin[x];
lin[x]=top;
}
void dfs_lca(int k,int fa){
gr[k][0]=fa;
deep[k]=deep[fa]+1;
for (int i=1;i<19;i++)
gr[k][i]=gr[gr[k][i-1]][i-1];
for (int i=lin[k];i;i=e[i].next)
if (fa^e[i].y) dfs_lca(e[i].y,k);
}
int LCA(int x,int y){
if (deep[x]<deep[y]) swap(x,y);
int dep=deep[x]-deep[y];
for (int i=0;i<19;i++)
if (dep>>i&1) x=gr[x][i];
for (int i=18;i>=0;i--)
if (gr[x][i]^gr[y][i]) x=gr[x][i],y=gr[y][i];
return x^y?gr[x][0]:x;
}
#define vt vector<int>::iterator
void dfs_up(int k){
int now=cnt[deep[k]+w[k]];
for (int i=lin[k];i;i=e[i].next)
if (e[i].y^gr[k][0]) dfs_up(e[i].y);
cnt[deep[k]]+=num[k];
ans[k]+=cnt[deep[k]+w[k]]-now;
for (vt it=q1[k].begin();it!=q1[k].end();it++)
cnt[deep[*it]]--;
}
void dfs_down(int k){
int now=cnt[w[k]-deep[k]+N];
for (int i=lin[k];i;i=e[i].next)
if (gr[k][0]^e[i].y) dfs_down(e[i].y);
for (vt it=q2[k].begin();it!=q2[k].end();it++)
cnt[*it+N]++;
ans[k]+=cnt[w[k]-deep[k]+N]-now;
for (vt it=q3[k].begin();it!=q3[k].end();it++)
cnt[*it+N]--;
}
#undef vt
Abigail into(){
scanf("%d%d",&n,&m);
int x,y;
for (int i=1;i<n;i++){
scanf("%d%d",&x,&y);
ins(x,y);ins(y,x);
}
for (int i=1;i<=n;i++)
scanf("%d",&w[i]);
for (int i=1;i<=m;i++)
scanf("%d%d",&s[i],&t[i]);
}
Abigail work(){
dfs_lca(1,0);
for (int i=1;i<=m;i++){
lca[i]=LCA(s[i],t[i]);
dis[i]=deep[s[i]]+deep[t[i]]-2*deep[lca[i]];
num[s[i]]++;
q1[lca[i]].push_back(s[i]);
q2[t[i]].push_back(dis[i]-deep[t[i]]);
q3[lca[i]].push_back(dis[i]-deep[t[i]]);
}
dfs_up(1);
dfs_down(1);
for (int i=1;i<=m;i++)
if (deep[s[i]]==deep[lca[i]]+w[lca[i]]) ans[lca[i]]--; //去重
}
Abigail outo(){
for (int i=1;i<=n;i++)
printf("%d ",ans[i]);
puts("");
}
int main(){
into();
work();
outo();
return 0;
}