问题描述:
每个分叉点及末梢可能有苹果(最多1个),每次可以摘掉一个苹果,或有一个苹果新长出来,随时查询某个分叉点往上的子树里,一共有多少个苹果(分叉点数量:100,000 )。深度优先遍历整个苹果树,为每个节点标记一个开始时间和结束时间(所有时间都不相同),显然子树里面所有节点的开始和结束时间,都位于子树树根的开始和结束时间之间。
问题变成:有n个节点,就有2n个开始结束时间,它们构成序列A1A2….A2n,序列里每个数是0或者1,可变化,随时查询某个区间里数的和。当然由于苹果树上每个放苹果的位置对应于数列里的两个数,所以结果要除以2
解决办法:
数据结构:一道树状数组的题。
操作:
1. 删/添
2.查和
问题:
1.把树横向压缩变成线性区间,套用树状数组
2.对树状数组的构建和使用都很模糊
这道代码题中并没有一个明确的a数组把整个序列描述出来并且构建C数组,是因为这道题中初始化的时候是a序列里都有一个苹果。
构建:
a[]
lowbit[i] = i&(i^(i-1));(长度是a序列的总长)
C[i] = a[i-lowbit(i)+1] + …+ a[i](两个for循环嵌套)
求和:
sum(k) = C[n1]+C[n2] + …+ C[nm](nm= k)
ni-1 =ni-lowbit(ni)(终止条件n1大于0)
a[i] + a[i+1] + … + a[j] = sum(j)-sum(i-1)
修改值:
C[n1], C[n2], …C[nm]
n1 = i ,
ni+1 = ni + lowbit(ni)
nm小于等于N
3.某些模板细节问题
(1)变量、函数、结构体命名大小写的使用
(2)深搜过程for循环里,dfs()里的参数应该是邻接表数组包含的值
(3)构建Lowbit和c数组时循环应是从1到n(注意边界范围)
(4)为啥不用%c读操作?因为会把回车符也读进去!
结构:
邻接表:模拟输入的苹果树分叉
树状数组公式
深度优先搜索:找每个分叉的开始时间结束时间
常量:
最大值:两倍!
涉及模糊知识点(待拓展):
树状数组
vector
dfs
menset
代码:
#include <iostream>
#include <vector>
#include <cstdio>
using namespace std;
#define MY_MAX 220000
int C[MY_MAX];
int Lowbit[MY_MAX];
bool HasApple[MY_MAX/2];
int Start[MY_MAX/2];
int End[MY_MAX/2];
int nCount = 0;
vector< vector<int> > G(MY_MAX/2);
void DFS(int v)
{
Start[v] = ++nCount;
for(int i = 0; i < (int)G[v].size(); i++)
DFS(G[v][i]);
End[v] = ++nCount;
}
int QuerySum(int p)
{
int sum = 0;
while(p > 0)
{
sum += C[p];
p -= Lowbit[p];
}
return sum;
}
void Modify(int p, int val)
{
while(p <= nCount)
{
C[p] += val;
p += Lowbit[p];
}
//C[p] += val;
}
int main()
{
int n;
scanf("%d", &n);
for(int i = 0; i < n - 1; i++)
{
int a, b;
scanf("%d%d", &a, &b);
G[a].push_back(b);
}
nCount = 0;
DFS(1);
/*
for(int u = 1; u <= n; u++)
{
cout << u<< " " << endl;
cout << Start[u] << " " << End[u] << endl << endl;
}*/
for(int i = 1; i <= n; i++)
HasApple[i] = 1;
for(int i = 1; i <= nCount; i++)
Lowbit[i] = i & (i ^ (i - 1));
for(int i = 1; i <= nCount; i++)
C[i] = i - (i - Lowbit[i] + 1) + 1;
int m;
scanf("%d", &m);
for(int i = 0; i < m; i++)
{
char cmd[10];
int k;
scanf("%s%d", cmd, &k);
if(cmd[0] == 'Q')
{
int sum1 = QuerySum(Start[k] - 1);
int sum2 = QuerySum(End[k]);
printf("%d\n", (sum2 - sum1)/2);
}
else if(cmd[0] == 'C')
{
if(HasApple[k])
{
Modify(Start[k], -1);
Modify(End[k], -1);
HasApple[k] = 0;
}
else
{
Modify(Start[k], 1);
Modify(End[k], 1);
HasApple[k] = 1;
}
}
}
return 0;
}