题意:

一棵苹果树有N个分叉,编号1---N(根的编号为1),每个分叉只能有一颗苹果或者没有苹果。 现在有两种操作:

1.某个分叉上的苹果从有变无或者从无边有。

2.需要统计以某个分叉为根节点时,它的子树上(包括该分叉)共有多少苹果。

分析: 有两种操作,基本就是使用数据结构维护的题目了。开始想了很久,不懂如何将分叉转化为一维线性的树状数组维护。 看了下discuss,有人说了时间戳三字。想了想,发现如果按照节点遍历的顺序可以制造出时间上的线性关系。 例如:

连接情况为:1---->2     1--->3    3--->4        3--->5

以1为根节点开始dfs,则遍历到每个点的时间可以为       1---->1     3--->2    4--->3    5---->4     2--->5

用两个数组begin,end统计以节点i为根时,遍历的第一个点的时间,和遍历最后一个点的时间

所以:begin[1] = 1 ;  end[1] = 5;   begin[2] = 5 ; end[2] = 5;   begin[3] = 2; end[3] = 4;........................................................

改变节点i的状态,时间戳小于i的会受影响;求和时,只需求(begin[i],end[i])的和了............................这样就变成了单点更新,区间求和的问题了。

#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <vector>
#include <set>
#include <queue>
#include <stack>
#include <climits>//形如INT_MAX一类的
#define MAX 100005
#define INF 0x7FFFFFFF
#define REP(i,s,t) for(int i=(s);i<=(t);++i)
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
#define mp(a,b) make_pair(a,b)
#define L(x) x<<1
#define R(x) x<<1|1
# define eps 1e-5
//#pragma comment(linker, "/STACK:36777216") ///传说中的外挂
using namespace std; int begin[MAX],end[MAX],cnt[MAX],vis[MAX];
int c[MAX];
int n,m,step;
char op;
struct node {
int s,e,next;
} ed[MAX];
int head[MAX],num; void init() {
memset(head,-1,sizeof(head));
num = 0;
step = 1;
memset(c,0,sizeof(c));
memset(cnt,1,sizeof(cnt));
memset(vis,0,sizeof(vis));
} void addedge(int s,int e) {
ed[num].s = s;
ed[num].e = e;
ed[num].next = head[s];
head[s] = num ++;
} int lowbit(int x) {
return x & (-x);
} void update(int x,int va) {
while(x > 0) {
c[x] += va;
x -= lowbit(x);
}
} int query(int x) {
int sum = 0;
while(x <= n) {
sum += c[x];
x += lowbit(x);
}
return sum;
} void dfs(int v0) {
vis[v0] = 1;
begin[v0] = step;
for(int i=head[v0]; i != -1; i = ed[i].next) {
int e = ed[i].e;
if(vis[e] == 0) {
step ++;
dfs(e);
}
}
end[v0] = step;
} int main() {
init();
scanf("%d",&n);
int x,y;
for(int i=0; i<n-1; i++) {
scanf("%d%d",&x,&y);
addedge(x,y);
}
dfs(1);
for(int i=1; i<=n; i++) update(i,1);
scanf("%d",&m);
for(int i=0; i<m; i++) {
getchar();
scanf("%c%d",&op,&x);
if(op == 'Q') {
printf("%d\n",query(begin[x]) - query(end[x] + 1));
}
if(op == 'C') {
cnt[x] ++;
if(cnt[x] % 2 == 0) update(begin[x],-1);
else update(begin[x],1);
}
}
return 0;
}

最新文章

  1. Lucene的分析资料【转】
  2. CSS选择器、CSS hack及CSS执行效率
  3. vim 中乱码问题
  4. Oracle使用goldengate分别向Oracle和mysql双路的单向复制
  5. shareplex的安装&amp;&amp;起停服务(添加新用户)
  6. 建立树莓派raspberry交叉编译环境以及编译内核
  7. Spring IOC之依赖
  8. 搭建免费wifi,嗅探接入该wifi的所有网络信息
  9. [转]html转码表
  10. 既然函数也是对象,那么为什么this不指向普通函数?
  11. js_3_for_if_try
  12. vim编辑器——常用操作整理
  13. HTML 样式设计
  14. 策略模式(Stratety)
  15. H5 文本属性
  16. 10.13 新版本go on~
  17. WCG distribution of byteball
  18. 在引用的laravel的@include子模板中传递参数
  19. 手机与PC的影音相互播放(DLNA/UPNP)
  20. 16 Linux系统的文件压缩、解压与归档

热门文章

  1. Linux系统编程(15)——shell脚本语法
  2. javadoc 生成帮助文档时,注意以下几点
  3. 在web应用程序中使用MemcachedClient
  4. Windows下安装Memcache
  5. js打印数据类型
  6. DWZ在APS.NET WebForm中的使用(二)
  7. SQL子句执行顺序和Join的一点总结
  8. struts2 &lt;s:iterator&gt; 遍历方法
  9. 【Android 错误记录】installation error: INSTALL_PARSE_FAILED_NO_CERTIFICATES 错误
  10. logfile提示stale错误解决方法