1. 程式人生 > >aoj2170(並查集操作更改)

aoj2170(並查集操作更改)

/*
translation:
	給出一棵樹,根節點為1。一開始只有根節點被標記。現在有兩種操作,一種是查詢某一節點最近的一個標記
	父節點,另外是將某一節點標記。求所有查詢父節點下標的和。
solution:
	按照題意,依次父節點遍歷即可。
note:
	#這道題一開始被歸類為並查集,害得我想了半天。並查集的路徑壓縮會破壞樹的父子節點的關係而此題又要
	維護父子節點的關係,形成矛盾。後來想可不可以不用路徑壓縮,又被自己否定了,因為題目沒說查詢的操作
	最多多少個。萬一查詢數量過多的話肯定超時!沒想到最後正好是不用壓縮路徑做的。淚。這題目明顯不科學!
	測試資料水。。。
date:
	2016.10.19
*/
#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;
const int maxn = 100000 + 5;
typedef long long ll;

int par[maxn], n, q;
bool marked[maxn];

int ancestor(int x)
{
	while(par[x] != x && !marked[x])	x = par[x];
	return x;
}

int main()
{
	//freopen("in.txt", "r", stdin);
	while(~scanf("%d%d", &n, &q))
	{
		if(n == 0 && q == 0)	break;
		memset(marked, 0, sizeof(marked));
		for(int i = 1; i <= n; i++)	par[i] = i;

		int p;	marked[1] = true;
		for(int i = 2; i <= n; i++)
		{
			scanf("%d", &p);
			par[i] = p;
		}

		char op;	int x;
		ll ans = 0;
		while(q--)
		{
			scanf("\n%c%d", &op, &x);
			if(op == 'M')	marked[x] = true;
			else			ans += ancestor(x);
		}
		printf("%lld\n", ans);
	}
}