ZOJ 3686 A A Simple Tree Problem

開始想了一個錯誤的算法,對每個節點保存它的子樹中的節點數目和其中爲一的數目,操作某節點時向上更新其祖先的數據(log N),查詢時直接輸出。當時忽略了操作同時也需要更新後代的數據,這樣的最壞複雜度是N,肯定是不行的。但直接交上去不是WA而是超時,由此猜想其中有類似鏈表的數據。

這個問題可以用線段樹很好地解決,在對原樹進行先序遍歷的同時標上序號後,可以將任意子樹轉化爲區間。序號介於某節點到它的任意後代間的點必爲該節點的後代,在這種排序下即可建立線段樹,將對子樹的操作轉化爲對區間的操作。


#include <stdio.h>
#include <memory.h>
#define N 100001
#define M 262144
#define Negate(x) label[x]=!label[x]
#define Comple(a, b) sum[a]=b-sum[a]

int right[N];
int first[N];
int next[N];
int num[N];
int sum[M];
bool label[M];

int a, b, ans;
int n, m, cnt;

void build(int index)
{
	int i = first[index];
	num[index] = ++ cnt;
	right[index] = cnt;
	while(i > 0)
	{
		build(i);
		if(right[i] > right[index])
			right[index] = right[i];
		i = next[i];
	}
}

void update(int cur, int l, int r)
{
	if(a<=l && b>=r)
	{
		Negate(cur);
		Comple(cur, r-l+1);
	}
	else
	{
		int mid = (l+r) >> 1;
		int x = cur<<1, y = x+1;
		if(label[cur] == true)
		{
			Negate(cur);
			Negate(x);
			Negate(y);
			Comple(x, mid-l+1);
			Comple(y, r-mid);
		}
		if(a <= mid)
			update(x, l, mid);
		if(b > mid)
			update(y, mid+1, r);
		sum[cur] = sum[x] + sum[y];
	}
}

void query(int cur, int l, int r)
{
	if (a<=l && b>=r)
		ans += sum[cur];
	else
	{
		int mid = (l+r) >> 1;
		int x = cur<<1, y = x+1;
		if(label[cur] == true)
		{
			Negate(cur);
			Negate(x);
			Negate(y);
			Comple(x, mid-l+1);
			Comple(y, r-mid);
		}
		if(a <= mid)
			query(x, l, mid);
		if(b > mid)
			query(y, mid+1, r);
		sum[cur] = sum[x] + sum[y];
	}
}

int main()
{
	int node;
	while(scanf("%d%d", &n, &m) != EOF)
	{
		memset(first, 0, sizeof(first));
		for(int i=2; i<=n; ++i)
		{
			scanf("%d", &node);
			next[i] = first[node];
			first[node] = i;
		}
		
		cnt = 0;
		build(1);

		memset(label, false, sizeof(label));
		memset(sum, 0, sizeof(sum));
	
		char c[5];
		for(int j=0; j<m; ++j)
		{
			scanf("%s", c);
			scanf("%d", &node);
			a = num[node];
			b = right[node];
			if(c[0] == 'q')
			{
				ans = 0;
				query(1, 1, n);
				printf("%d\n", ans);
			}
			else if(c[0] == 'o')
				update(1, 1, n);
		}
		printf("\n");
	}
	return 0;
}


發佈了28 篇原創文章 · 獲贊 0 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章