https://www.luogu.org/problemnew/show/P3258
(树剖裸题
树上差分 = = 差分 + lca
1. 树上差分基本思想:和差分一样,用前缀和的思想来处理解(操作后的树上,任意节点的糖果数 是通过所有与其相连的子节点的和 以及该节点在差分数组里的值 得到的(dfs);
2. 因为这道题并不需要除了lca以外的信息,故tarjan
对于一组修改u,v :只需修改差分数组 ----- diff[u]++, diff[v], diff[lca(u,v)]--, diff[fa[lca(u,v)]]--
至于为什么,看1;
剩下自己想;;
// 15owzLy1
//luogu3258.cpp
//2018 09 25 18:45:43
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
typedef long long ll;
typedef double db;
using namespace std; const int N = ;
struct node {
int next, to;
}edge[N<<];
int set_[N], candy[N], diff[N], n, head[N], head_q[N], fa[N];
int query[N][], a, b, c, cnt;
bool vis[N]; template<typename T>inline void read(T &x_) {
x_=;bool f_=;char c_=getchar();
while(c_<''||c_>''){f_|=(c_=='-');c_=getchar();}
while(c_>=''&&c_<=''){x_=(x_<<)+(x_<<)+(c_^);c_=getchar();}
x_=f_?-x_:x_;
} inline void jb(int u, int v) {
edge[++cnt].to=v;
edge[cnt].next=head[u];
head[u]=cnt;
} int get_set_(int x) {
return (set_[x]==x)?x:set_[x]=get_set_(set_[x]);
} inline void Merge(int x, int y) {
set_[get_set_(y)]=get_set_(x);
} void dfs(int u) {
vis[u]=true;
for(int i=head[u];i;i=edge[i].next) {
int v=edge[i].to;
if(v==fa[u]) continue;
fa[v]=u;
dfs(v);
Merge(u, v);
} if(vis[query[u][]]) {
a=get_set_(query[u][]);
if(a!=get_set_(u)) {
diff[a]--, diff[fa[a]]--;
diff[u]++, diff[query[u][]]++;
}
}
if(vis[query[u][]]) {
a=get_set_(query[u][]);
if(a!=get_set_(u)) {
diff[a]--, diff[fa[a]]--;
diff[query[u][]]++, diff[u]++;
}
}
} void get_ans(int u) {
candy[u]=diff[u];
for(int i=head[u];i;i=edge[i].next) {
int v=edge[i].to;
if(v==fa[u]) continue;
get_ans(v);
candy[u]+=candy[v];
}
} int main() {
#ifndef ONLINE_JUDGE
freopen("luogu3258.in","r",stdin);
freopen("luogu3258.out","w",stdout);
#endif
int x, y, a1;
read(n); read(x); a1=x;
for(int i=;i<n;i++) {
read(y);
query[y][]=x, query[x][]=y;
x=y;
} for(int i=;i<n;i++) read(x), read(y), jb(x, y), jb(y, x);
for(int i=;i<=n;i++) set_[i]=i;
dfs(); get_ans(); candy[a1]++;
for(int i=;i<=n;i++)
printf("%d\n", candy[i]-);
return ;
}