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

链接: 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\n",sum[tid[i]]);
        else printf("%d\n",sum[tid[i]]-1);
    }
    return 0;
}

 

posted @ 2018-10-17 20:43  冥想选手  阅读(142)  评论(0编辑  收藏  举报