一个星期前,被USACO上的一个题卡住了,我一看就是一道二维线段树的题目, 就和POJ上1177 Picture差不多。所以就意味着我要重新学习一下线段树, 再研究Picture这个题(上次研究过一段时间,最后放弃了),就这么东找西找就 找到了这个题,试图用线段树做这个题,但是无从下手,不知道如何把题目中的 n-1对u和v转换成数,百度一下找人家的解题报告,看了很多,还是不懂, 还是那句话:看别人的代码学习算法很难受啊。 后来发现大家都用的一个叫做“树状数组”的东西,于是就研究了一下,发现“树状数组” 确实是个好东西。最后在这里看懂了用“树状数组”解本题的方法:
http://blog.csdn.net/logic_nut/archive/2009/09/22/4579215.aspx
再把自己的代码修改,神啦,终于A了,虽然时间是1000+M。我也不管了,
/**
刚开始被题目中的图片误导了,以为只是二叉树,写出了代码,WA了,
后来才发现,原来是多叉树,这就不好处理了,于是就用了树的
"孩子链存储方式",好不容易修改完了,提交,悲剧的TLE。。。
没办法,还是看看大家都在讨论的“树状数组”。看别人的代码来学习
一种算法,真是一件痛苦的事情啊。。。。。
最后终于懂了“树状数组”是一个什么东东。
而对于这题,难点在于:怎么把题目中的树映射成树状数组。。
**/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct CH
{
int idx;
struct CH *nxt;
} CHILD;
typedef struct N
{
int index; //在树状数组中的编号
int minIdx; //其所有子结点中的最小编号
CHILD *chld; //孩子链指针
} NODE;
/* 使用孩子链的存储方式 */
NODE fork[100005];
char vst[100005];
char apple[100005];
int n, cnt;
int treeArr[100005];
/* 认为y是x的孩子结点,
在fork[x].chld中前插一个结点,
结点的idx值为y */
void addChild(int x, int y)
{
CHILD *p;
p = (CHILD*)malloc(sizeof(CHILD));
p->idx = y;
p->nxt = fork[x].chld;
fork[x].chld = p;
}
/* 后序遍历树,更新各个结点在树状数组中的
编号index,和其子结点中的最小编号minIdx*/
void DFS(int r)
{
CHILD *p;
vst[r] = 1;
fork[r].minIdx = cnt; //这个的原因自己领会
p = fork[r].chld;
while (p)
{
if (vst[p->idx] == 0) //如果p->idx已经被访问过了,就说明p->idx不是r的孩子,而是r的父节点
DFS(p->idx);
p = p->nxt;
}
fork[r].index = cnt++; //最后遍历根结点
}
/* 以下这三个函数都是涉及树状数组的 */
int lowbit(int i)
{
return i&(-i);
}
int Sum(int i)
{
int sum = 0;
while(i > 0)
{
sum += treeArr[i];
i = i-lowbit(i);
}
return sum;
}
void Change(int i)
{
int t = 1;
if(apple[i]) t = -1;
apple[i] += t;
while(i <= n)
{
treeArr[i] += t;
i = i+lowbit(i);
}
}
/* ******************************* */
int main()
{
int m, i, j, u, v;
int fk, sum;
char ch;
memset(fork, 0, sizeof(fork));
memset(apple, 1, sizeof(apple)); //初始每个枝上都有苹果
scanf("%d", &n);
for (i=1; i<n; i++)
{
scanf("%d %d", &u, &v);
addChild(u, v); //v是u的孩子
addChild(v, u); //u是v的孩子
}
cnt = 1;
DFS(1); //后序遍历
for (i=1; i<=n; i++)
treeArr[i] = lowbit(i); //建立树状数组treeArr[]
scanf("%d", &m);
while (m--)
{
getchar();
scanf("%c %d", &ch, &fk);
if ('C' == ch)
Change(fork[fk].index);
else
printf("%d/n", Sum(fork[fk].index)-Sum(fork[fk].minIdx-1));
}
return 0;
}