BZOJ1103 POI2007 大都市

这题目的意思大致就是本来有一棵所有边的权都是1的树、然后经过若干次操作把所有边的权值都变成0、中间会让你求根到一个点的权值和、

本来想过树链剖分、后来看看数据范围和如此弱的操作又感觉不是、、

然后分析一下、、这题就是快速求一个链上的数字和、、比如我们现在考虑根、就是相当于把根的所有子孙权值和剪掉这个儿子之外的所有儿子的子孙权值和、、

也就是说、每个点的权值只在它和它的子孙上有效、、

于是、、想到了DFS序、、每当访问到一个点、就在对应时间戳的位置+1、离开的时候在对应时间戳-1、

抹杀的时候就把两个时间戳都刷成0就好了、、

至于询问、、求个前缀和BIT大家都懂、、

 

Code:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cmath>
#include <cstring>

#define lowbit(x) (x&(-x))

using namespace std;

int n,m,a,b,tt=0,r=0;
int fa[250010],num[500010],f1[250010],f2[250010];
int g[250010],e[250010],t[500010],next[500010];
char ch;

void add(int x,int d){
	while	(x<=2*n){
		num[x]+=d;
		x+=lowbit(x);
	}
}

int cnt(int x){
	int cur=0;
	while	(x){
		cur+=num[x];
		x-=lowbit(x);
	}
	return	cur;
}

void dfs(int cur){
	++tt;f1[cur]=tt;add(tt,1);
	for	(int u=g[cur];u;u=next[u])
		if	(fa[cur]!=t[u]){
			fa[t[u]]=cur;
			dfs(t[u]);
		}
	++tt;f2[cur]=tt;add(tt,-1);
}

void addedge(int a,int b){
	t[++r]=b;
	if	(g[a])	{next[e[a]]=r;e[a]=r;}
	else	g[a]=e[a]=r;
}

int main(){
	scanf("%d",&n);
	for	(int i=1;i<n;i++){
		scanf("%d%d",&a,&b);
		addedge(a,b);
		addedge(b,a);
	}
	dfs(1);
	scanf("%d",&m);
	ch=getchar();
	m+=n-1;
	while	(m--){
		scanf("%c%d",&ch,&a);
		if	(ch=='A'){
			scanf("%d\n",&b);
			if	(fa[a]==b)	swap(a,b);
			add(f1[b],-1);
			add(f2[b],1);
		}
		else{
			printf("%d\n",cnt(f1[a])-1);
			ch=getchar();
		}
	}
	return	0;
}

  

你可能感兴趣的:(2007)