Description

Given a rooted tree, each node has a boolean (0 or 1) labeled on it. Initially, all the labels are 0.

We define this kind of operation: given a subtree, negate all its labels.

And we want to query the numbers of 1's of a subtree.

Input

Multiple test cases.

First line, two integer N and M, denoting the numbers of nodes and numbers of operations and queries.(1<=N<=100000, 1<=M<=10000)

Then a line with N-1 integers, denoting the parent of node 2..N. Root is node 1.

Then M lines, each line are in the format "o node" or "q node", denoting we want to operate or query on the subtree with root of a certain node.

Output

For each query, output an integer in a line.

Output a blank line after each test case.

题目大意:给一棵多叉树,初始值都为0,o x为翻转以x为根的子树,q x为查询以x为根的子树有多少个1

思路:这数据范围,暴力是不行的,怎么暴力都是不行的>_<。这题的要求是:修改一大片、查询一大片,比较容易想到的就是线段树(树状数组也可以,不过要翻转嘛……好像有难度……反正我不会>_<)。问题是这玩意儿怎么转换成线段树呢?要转化成线段树,就要把每个点的子孙们都放到一片连续的空间里。这时,若使用DFS,遍历的顺序刚刚好符合要求,于是我们就DFSo(∩_∩)o 。DFS途中就可以算出每个点的及其子孙覆盖的区域。然后变成线段树之后呢,随便搞搞就行了o(∩_∩)o

 #include <cstdio>
#include <cstring> const int MAX = ; int flip[MAX*], sum[MAX*], cnt[MAX*];//tree
int head[MAX], next[MAX], to[MAX], ecnt;
int beg[MAX], size[MAX], dfs_clock;
int y1, y2; void tle() {while() ;} void init() {
ecnt = ;
dfs_clock = ;
memset(head, , sizeof(head));
memset(flip, , sizeof(flip));
memset(cnt, , sizeof(cnt));
} void add_edge(int u, int v) {
to[ecnt] = v; next[ecnt] = head[u]; head[u] = ecnt++;
} void dfs(int x) {
size[x] = ;
beg[x] = ++dfs_clock;
for(int p = head[x]; p; p = next[p]) {
dfs(to[p]);
size[x] += size[to[p]];
}
} void maintain(int x, int l, int r) {
int lc = x * , rc = x * + ;
if(l < r) {
cnt[x] = cnt[rc] + cnt[lc];
}
} void pushdown(int x) {
int lc = x * , rc = x * + ;
if(flip[x]) {
flip[x] = ;
flip[lc] ^= ;
cnt[lc] = sum[lc] - cnt[lc];
flip[rc] ^= ;
cnt[rc] = sum[rc] - cnt[rc];
}
} void update(int x, int l, int r) {
int lc = x * , rc = x * + ;
if(y1 <= l && r <= y2) {
flip[x] ^= ;
cnt[x] = sum[x] - cnt[x];
}
else {
pushdown(x);
int mid = (l + r) / ;
if(y1 <= mid) update(lc, l, mid);
if(mid < y2) update(rc, mid + , r);
maintain(x, l, r);
}
} int ans; void query(int x, int l, int r) {
int lc = x * , rc = x * + ;
if(y1 <= l && r <= y2) ans += cnt[x];
else {
pushdown(x);
int mid = (l + r) / ;
if(y1 <= mid) query(lc, l, mid);
if(mid < y2) query(rc, mid + , r);
}
} void build(int x, int l, int r) {
int lc = x * , rc = x * + ;
if(l == r) {
sum[x] = ;
}
else {
int mid = (l + r) / ;
build(lc, l, mid);
build(rc, mid + , r);
sum[x] = sum[lc] + sum[rc];
}
} int main() {
int n, m, x;
char c[];
while(scanf("%d%d", &n, &m) != EOF) {
init();
for(int i = ; i <= n; ++i) {
scanf("%d", &x);
add_edge(x, i);
}
dfs();
build(, , n);
while(m--) {
scanf("%s%d", c, &x);
y1 = beg[x]; y2 = beg[x] + size[x] - ;
if(c[] == 'o') {
update(, , n);
}
if(c[] == 'q') {
ans = ;
query(, , n);
printf("%d\n", ans);
}
}
puts("");
}
}

ZOJ 3686 A Simple Tree Problem(线段树)的更多相关文章

  1. ZOJ 3686 A Simple Tree Problem

    A Simple Tree Problem Time Limit: 3 Seconds      Memory Limit: 65536 KB Given a rooted tree, each no ...

  2. zoj 3686 A Simple Tree Problem (线段树)

    Solution: 根据树的遍历道的时间给树的节点编号,记录下进入节点和退出节点的时间.这个时间区间覆盖了这个节点的所有子树,可以当做连续的区间利用线段树进行操作. /* 线段树 */ #pragma ...

  3. ZOJ-3686 A Simple Tree Problem 线段树

    题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3686 题意:给定一颗有根树,每个节点有0和1两种值.有两种操作: ...

  4. bzoj 3489 A simple rmq problem - 线段树

    Description 因为是OJ上的题,就简单点好了.给出一个长度为n的序列,给出M个询问:在[l,r]之间找到一个在这个区间里只出现过一次的数,并且要求找的这个数尽可能大.如果找不到这样的数,则直 ...

  5. hdu 4973 A simple simulation problem. (线段树)

    题目链接 题意: 给定n长的序列 m个操作 序列默认为 1, 2, 3···n 操作1:D [l,r] 把[l,r]区间增长 :( 1,2,3,4 进行 D [1,3]变成 1,1,2,2,3,3,4 ...

  6. BNU 28887——A Simple Tree Problem——————【将多子树转化成线段树+区间更新】

    A Simple Tree Problem Time Limit: 3000ms Memory Limit: 65536KB This problem will be judged on ZJU. O ...

  7. 【BZOJ4999】This Problem Is Too Simple!(线段树)

    [BZOJ4999]This Problem Is Too Simple!(线段树) 题面 BZOJ 题解 对于每个值,维护一棵线段树就好啦 动态开点,否则空间开不下 剩下的就是很简单的问题啦 当然了 ...

  8. xtu数据结构 I. A Simple Tree Problem

    I. A Simple Tree Problem Time Limit: 3000ms Memory Limit: 65536KB 64-bit integer IO format: %lld     ...

  9. hdu 5274 Dylans loves tree(LCA + 线段树)

    Dylans loves tree Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Othe ...

随机推荐

  1. python人工智能爬虫系列:怎么查看python版本_电脑计算机编程入门教程自学

    首发于:python人工智能爬虫系列:怎么查看python版本_电脑计算机编程入门教程自学 http://jianma123.com/viewthread.aardio?threadid=431 本文 ...

  2. 简单几行代码使用百度地图API接口分页获取信息

    首发于: 万能助手扩展开发:使用百度地图API接口分页获取信息_电脑计算机编程入门教程自学 http://jianma123.com/viewthread.aardio?threadid=426 使用 ...

  3. LeetCode 中级 -二叉树的层次遍历(102)

    题目描述: 给定一个二叉树,返回其按层次遍历的节点值. (即逐层地,从左到右访问所有节点). 例如:给定二叉树: [3,9,20,null,null,15,7], 3 / \ 9 20 / \ 15 ...

  4. 前端jQuery实现瀑布流

    瀑布流是我们经常会见到的东西,一直刷新一直有,其实它实现起来是很简单的.具体代码如下 1.css代码 <style> *{ margin:; padding:; } .container{ ...

  5. sea.js模块化工具

    sea.js 一. sea.js向全局中引入了两个变量seajs.define: 1.seajs用加载文件 seajs.use(deps,callback)异步引入入口模块 路径要以sea.js文件所 ...

  6. GitLab 基本操作

    登录 在浏览其中输入http://192.168.3.11:8888 如图1登录界面.   图1 注:第一次新增用户,会发送修改密码链接到用户的邮箱中,用户会收到如图2邮件. 图2 2. 修改密码 点 ...

  7. 通过samba服务将centos7指定文件挂载到window下

    做嵌入式开发,windows下编辑代码,虚拟机上编译,为了方便打算在虚拟机下搭一个samba服务器,将文件夹映射到windows下,搜索网上的方法,内容大同小异,试了半天终于成功了.特此记录一下步骤, ...

  8. python学习笔记:第18天 面向对象04-反射

    目录 issubclass和isinstance 区分函数和方法 反射 issubclass和isinstance issubclass:可以判断一个类是否另一个类的子类. # issubclass ...

  9. 树形DP(例题)

    没有上司的舞会 题目 Ural大学有N个职员,编号为1~N.他们有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司.每个职员有一个快乐指数.现在有个周年庆宴会,要求与会职 ...

  10. FPGA学习之路——PLL的使用

    锁相环(PLL)主要用于频率综合,使用一个 PLL 可以从一个输入时钟信号生成多个时钟信号. PLL 内部的功能框图如下图所示: 在ISE中新建一个PLL的IP核,设置四个输出时钟,分别为25MHz. ...