树状数组【bzoj1782】: [Usaco2010 Feb]slowdown 慢慢游

【bzoj1782】: [Usaco2010 Feb]slowdown 慢慢游

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会放慢自己的速度,防止打扰他的朋友。

网上正统做法是线段树。

树状数组也可以,很容易写。

按照dfn序建树。

code:

#include <iostream>
#include <cstdio>

using namespace std;

const int wx=200017;

inline int read(){
	int sum=0,f=1; char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
	while(ch>='0'&&ch<='9'){sum=(sum<<1)+(sum<<3)+ch-'0'; ch=getchar();}
	return sum*f;
}

int sum[wx],dfn[wx];
int head[wx],num,size[wx];
int n,m,tot;

struct e{
	int nxt,to;
}edge[wx*2];

void add(int from,int to){
	edge[++num].nxt=head[from];
	edge[num].to=to;
	head[from]=num;
}

void dfs(int u,int fa){
	dfn[u]=++tot;size[u]=1;
	for(int i=head[u];i;i=edge[i].nxt){
		int v=edge[i].to;
		if(v==fa)continue;
		dfs(v,u);size[u]+=size[v];
	}
}

void Add(int pos,int k){
	for(int i=pos;i<=n;i+=(i&-i)){
		sum[i]+=k;
	}
}

int query(int x){
	int re=0;
	for(int i=x;i>=1;i-=(i&-i)){
		re+=sum[i];
	}
	return re;
}

int main(){
	n=read();
	for(int i=1;i<n;i++){
		int x,y;
		x=read(); y=read();
		add(x,y); add(y,x);
	}
	dfs(1,0);
	for(int i=1;i<=n;i++){
		int x;x=read();
		printf("%d\n",query(dfn[x]));
		Add(dfn[x],1);Add(dfn[x]+size[x],-1);
	}
	return 0;
}
posted @ 2018-10-19 14:26  _王小呆  阅读(181)  评论(0编辑  收藏  举报