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;
}

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

783

被折叠的 条评论
为什么被折叠?



