bzoj 3631 松鼠的新家 (树链剖分)

时间:2023-03-08 22:25:58

链接: https://www.lydsy.com/JudgeOnline/problem.php?id=3631

思路:

直接用树链剖分求每一次运动,因为这道题只需要区间增添,单点求值,没必要用线段树,直接数组标记下就好了

实现代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define mid int m = (l + r) >> 1 const int M = 1e5 + ;
int cnt,cnt1;
int head[M],dep[M],fa[M],top[M],son[M],siz[M],tid[M],sum[M],a[M]; struct node{
int to,next;
}e[M]; void add(int u,int v){
e[++cnt].to = v;e[cnt].next = head[u];head[u] = cnt;
} void dfs1(int u,int faz,int deep){
dep[u] = deep;
fa[u] = faz;
siz[u] = ;
for(int i = head[u];i;i=e[i].next){
int v = e[i].to;
if(v == fa[u]) continue;
dfs1(v,u,deep+);
siz[u] += siz[v];
if(siz[v] > siz[son[u]]||son[u] == -)
son[u] = v;
}
} void dfs2(int u,int t){
top[u] = t;
tid[u] = ++cnt1;
if(son[u] == -) return ;
dfs2(son[u],t);
for(int i = head[u];i;i=e[i].next){
int v = e[i].to;
if(v != fa[u]&&v != son[u])
dfs2(v,v);
}
} void update(int x,int y){
sum[x]++;
sum[y+]--;
} void solve(int x,int y){
int fx = top[x],fy = top[y];
int ans = ;
while(fx!=fy){
if(dep[fx] < dep[fy]) swap(x,y),swap(fx,fy);
update(tid[fx],tid[x]);
x = fa[fx]; fx = top[x];
}
if(dep[x] > dep[y]) swap(x,y);
update(tid[x],tid[y]);
} int main(){
int n,x,y;
scanf("%d",&n);
memset(son,-,sizeof(son));
for(int i = ;i <= n;i ++){
scanf("%d",&a[i]);
}
int n1 = n-;
while(n1--){
scanf("%d%d",&x,&y);
add(x,y); add(y,x);
}
dfs1(,,); dfs2(,);
for(int i = ;i <= n;i ++)
solve(a[i-],a[i]);
for(int i = ;i <= n;i ++){
sum[i] += sum[i-];
}
// cout<<<<endl;
for(int i = ;i <= n;i ++){
if(i == ) printf("%d\n",sum[tid[i]]);
else printf("%d\n",sum[tid[i]]-);
}
return ;
}