链接: 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 + 10; 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] = 1; for(int i = head[u];i;i=e[i].next){ int v = e[i].to; if(v == fa[u]) continue; dfs1(v,u,deep+1); siz[u] += siz[v]; if(siz[v] > siz[son[u]]||son[u] == -1) son[u] = v; } } void dfs2(int u,int t){ top[u] = t; tid[u] = ++cnt1; if(son[u] == -1) 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+1]--; } void solve(int x,int y){ int fx = top[x],fy = top[y]; int ans = 0; 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,-1,sizeof(son)); for(int i = 1;i <= n;i ++){ scanf("%d",&a[i]); } int n1 = n-1; while(n1--){ scanf("%d%d",&x,&y); add(x,y); add(y,x); } dfs1(1,0,1); dfs2(1,0); for(int i = 2;i <= n;i ++) solve(a[i-1],a[i]); for(int i = 1;i <= n;i ++){ sum[i] += sum[i-1]; } // cout<<1<<endl; for(int i = 1;i <= n;i ++){ if(i == 1) printf("%d ",sum[tid[i]]); else printf("%d ",sum[tid[i]]-1); } return 0; }