我一直不知道树状数组和线段树有什么区别,算法不同,但我感觉他们解决的问题差不多。
由于此题数据比较大(N<=10^5),而且不是标准的二叉树,所以这里我们队每一个节点重新编号,
另外为每一个节点赋一个左值和一个右值,表示这个节点的管辖范围。
这样有了每个节点的左值和右值就可以用树状数组解决了
树状数组详解:http://blog.csdn.net/clx55555/article/details/52261538
#include<iostream>
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
#define mem(a) memset(a, 0, sizeof(a))
#define MAXN 100010
int TreeArray[MAXN], Left[MAXN], Right[MAXN], Fork[MAXN];
typedef vector<int> Ve;
vector<Ve>Edge(MAXN);
int N,M;
int key;
void init()//初始化数组和
{
mem(Left); mem(Right);
mem(Fork); mem(TreeArray);
for(int i=0;i<MAXN;i++)Edge[i].clear();
}
void dfs(int node)
{
Left[node]=key;
for(int i=0;i<Edge[node].size();i++)
{
key+=1;
dfs(Edge[node][i]);
}
Right[node]=key;
}
int LowBit(int x)
{
return x&(x^(x-1));
}
void Edit(int k,int num)
{
while(k<=N)
{
TreeArray[k]+=num;
k+=LowBit(k);
}
}
int GetSum(int k)//得到1...k的和
{
int sum = 0;
while(k>=1)
{
sum += TreeArray[k];
k -= LowBit(k);
}
return sum;
}
void ReadDataAndDo()
{
int a,b;
char ch;
for(int i=1;i<N;i++)
{
scanf("%d%d",&a,&b);
Edge[a].push_back(b);
}
key=1;
dfs(1);
for(int i=1;i<=N;i++)
{
Fork[i]=1;
Edit(i,1);
}
scanf("%d%*c",&M);
for(int i=0;i<M;i++)
{
scanf("%c %d%*c",&ch,&b);
if(ch=='Q')
printf("%d\n",GetSum(Right[b])-GetSum(Left[b]-1));
else
{
if(Fork[b])Edit(Left[b],-1);
else Edit(Left[b],1);
Fork[b]=!Fork[b];
}
}
}
int main() {
while(~scanf("%d",&N))
{
init();
ReadDataAndDo();
}
return 0;
}
本文介绍了一种使用树状数组解决特定树形结构问题的方法。通过重新编号树节点并赋予每个节点左值和右值来定义其管辖范围,进而利用树状数组高效地进行查询和更新操作。

637

被折叠的 条评论
为什么被折叠?



