poj3321 Apple Tree ****

/*
  看了网上的代码。。再自己写了一个。。。
( 网上很多代码都是默认输入的数据u是v的父节点。。  也能AC。。  但不严谨。。)
【转】
思路:树状数组。这道题重点怎么建立树到树状数组的映射关系:利用dfs遍历树,
对每个节点进行两次编号,第一次搜到第i个节点时的深度dep,
为这个节点管辖区间的上限low[i](也为这个节点的下标),然后搜这个节点的子节点,
最后搜回来后的深度dep,为这个节点管辖区间的下限high[i]。接下来就是树状数组部分了。
*/

/*

* 3321
* 邻接表建树+树状数组
*
*/
#include
<cstdio>
using namespace std;

const int MAXN = 100000 + 5;
struct SData{ //节点
int value;
SData
*next;
};
SData edgehead[MAXN];
//邻接表

bool vis[MAXN] = {};
int n, m, u, v, dep = 0, s; //n,m,u,v同题意。。 s为命令里的数字
int low[MAXN], high[MAXN]; //上、下限
bool apple[MAXN]; //是否有苹果
int c[MAXN] = {}; //树状数组
char cmd; //命令

//dfs
void dfs(int x){
low[x]
= ++dep;
vis[x]
= 1;

SData
*p = edgehead[x].next;
while(p){
if(!vis[p->value])
dfs(p
->value);
p
= p->next;
}
high[x]
= dep;
}

int lowbit(int x){
return x & (-x);
}

void update(int x, int delta){
for(int i=x; i<=n; i+=lowbit(i)){
c[i]
+= delta;
}
}

int sum(int x){
int ans = 0;
for(int i=x; i>0; i-=lowbit(i)){
ans
+= c[i];
}
return ans;
}

int main(){
scanf(
"%d", &n);
for(int i=1; i<n; i++){
scanf(
"%d %d", &u, &v);

//邻接表建树
SData *p = new SData;
p
->value = v;
p
->next = edgehead[u].next;
edgehead[u].next
= p;

SData
*q = new SData; //注意反过来也要建。(若默认u是v的父节点,则可省略)
q->value = u;
q
->next = edgehead[v].next;
edgehead[v].next
= q;
}
dfs(
1);

//起始时刻每个节点都有苹果
for(int i=1; i<=n; i++){
apple[i]
= 1;
update(i,
1);
}

//命令
scanf("%d", &m);

for(int i=0; i<m; i++){
scanf(
"%c", &cmd);
scanf(
"%c %d", &cmd, &s);

if(cmd == 'C'){
int delta;
apple[s]
= !apple[s];
delta
= (apple[s] == 1 ? 1 : -1);
update(low[s], delta);
//low[s]也代表s在数组中的位置
}
else if(cmd == 'Q'){
int ans = sum(high[s]) - sum(low[s]-1);
printf(
"%d\n", ans);
}
}

return 0;
}

原文地址:https://www.cnblogs.com/longdouhzt/p/2103414.html