bzoj 3631

博客提及树上差分裸题,虽未展开内容,但核心围绕树上差分这一信息技术领域算法相关题目。树上差分是算法领域的一种方法,常用于解决树上路径问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

树上差分裸题

#include<bits/stdc++.h>
using namespace std;
typedef int lint;
const int maxn = 300000 + 5;
const int maxm = 600000 + 5;
lint a[maxn],ver[maxm],he[maxn],ne[maxm],tot,ans[maxn],val[maxn];
lint d[maxn],vis[maxn],f[maxn][21];
void add( lint x,lint y ){
    ver[++tot] = y;
    ne[tot] = he[x];
    he[x] = tot;
}
void init(){
    memset( he,0,sizeof(he) );
    tot = 1;

}
queue<lint> que;
void build(){
    d[1] = 0;
    que.push(1);
    vis[1]  = 1;
    while( que.size() ){
        lint x = que.front();
        que.pop();
        for( lint cure = he[x];cure;cure = ne[cure] ){
            lint y = ver[cure];
            if( y == f[x][0] ) continue;
            que.push(y);
            d[y] = d[x] + 1;
            f[y][0] = x;
            for( lint i = 1; (1<< i) <= d[y];i++ ){
                f[y][i] = f[ f[y][i-1] ][i-1];
            }
        }
    }
}
lint lca( lint x,lint y ){
    if( d[x] < d[y] ) swap( x,y );
    for( lint i = 20;i >= 0;i-- ){
        if( f[x][i] && d[f[x][i]] >= d[y]  ) x = f[x][i];
    }
    if( x == y ) return x;
    for(  lint i = 20;i >= 0;i-- ){
        if(  f[x][i]  !=  f[y][i]  ){
            x = f[x][i];
            y = f[y][i];
        }
    }
    return f[x][0];
}
lint dfs( lint x,lint fa ){
    lint sum = val[x];
    for( lint cure = he[x];cure;cure = ne[cure] ){
        lint y = ver[cure];
        if( y == fa ) continue;
        sum += dfs( y,x );
    }
    ans[x] = sum;
    return sum;
}
int main(){
    lint n;
    init();
    scanf("%d",&n);
    for( int i = 1;i <= n;i++ ) scanf("%d",&a[i]);
    for( lint  x,y,i = 1;i <= n-1;i++ ){
        scanf("%d%d",&x,&y);
        add(x,y);add(y,x);
    }
    build();
    for( lint i = 1;i <= n-1;i++ ){
        lint y = lca( a[i],a[i+1] );
        val[ f[y][0] ] -= 1;
        val[y] -= 1;
        val[ a[i] ] +=1;
        val[ a[i+1] ] += 1;
    }
    dfs(1,0);
    for( lint i = 1;i <= n;i++ ){
        if( i != a[1]  ){
            printf("%d\n", ans[i]-1 );
        }else{
            printf("%d\n", ans[i] );
        }
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值