BZOJ 1782 [Usaco2010 Feb]slowdown慢慢游 树状数组

解决一个关于奶牛从粮仓走向各自牧场的问题,利用DFS遍历和树状数组进行节点维护,统计每只奶牛在前往指定牧场的过程中需要减速避让其他奶牛的次数。

Description

每天Farmer John的N头奶牛(1 <= N <= 100000,编号1…N)从粮仓走向他的自己的牧场。牧场构成了一棵树,粮仓在1号牧场。恰好有N-1条道路直接连接着牧场,使得牧场之间都恰好有一条路径相连。第i条路连接着A_i,B_i,(1 <= A_i <= N; 1 <= B_i <= N)。奶牛们每人有一个私人牧场P_i (1 <= P_i <= N)。粮仓的门每次只能让一只奶牛离开。耐心的奶牛们会等到他们的前面的朋友们到达了自己的私人牧场后才离开。首先奶牛1离开,前往P_1;然后是奶牛2,以此类推。当奶牛i走向牧场P_i时候,他可能会经过正在吃草的同伴旁。当路过已经有奶牛的牧场时,奶牛i会放慢自己的速度,防止打扰他的朋友。 考虑如下的牧场结构(括号内的数字代表了牧场的所有者)。

Input

  • 第1行 : 一个正整数N * 第2…N行: 第i+1行包括一对正整数A_i,B_i
  • 第N+1..N+N行: 第 N+i行 包括一个正整数: P_i

Output

  • 第一行到第N行:第i行表示第i只奶牛需要被放慢的次数

Sample Input

5
1 4
5 4
1 3
2 4
4
2
1
5
3

Sample Output

0
1
0
2
1

题解:

发现一头牛到了之后会影响其所有子树的点,于是我们dfs一遍,把一个u,也即当前这个子树,然后往下dfs,用树状数组来维护,每次累加之后看路上有多少牛即可


#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int MAXN = 100005;
int n, pos[MAXN], ans[MAXN], head[MAXN] ,C[MAXN], tail;
struct Line{ int to, nxt; } line[ MAXN * 2 ];
void add_line( int from, int to ) { line[++tail].nxt = head[from]; head[from] = tail; line[tail].to = to; }
int lowbit( int x ) { return x & ( -x ); }
void modify( int x, int val ) {
    while( x <= n ) {
        C[x] += val;
        x += lowbit(x);
    }
}
int query( int x ) {
    int tmp = 0;
    while( x ) {
        tmp += C[x];
        x -= lowbit(x);
    }
    return tmp;
}
void dfs( int u, int fa ) {
    ans[pos[u]] = query( pos[u] );
    modify( pos[u], 1 );
    for( register int i = head[u]; i; i = line[i].nxt ) {
        int v = line[i].to;
        if( v == fa) continue;
        dfs( v, u );
    }
    modify( pos[u], -1 );
}
int main( ) {
    scanf( "%d", &n ); int ff, tt, tmp;
    for( register int i = 1; i <= n - 1; i++ ) { scanf( "%d%d", &ff, &tt ); add_line( ff, tt ); add_line( tt, ff ); }
    for( register int i = 1; i <= n; i++ ) scanf( "%d", &tmp), pos[tmp] = i;
    dfs( 1, 0 );
    for( register int i = 1; i <= n; i++ ) printf( "%d\n", ans[i] );
    return 0;
}

这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值