您的位置:首页 > 其它

zoj 3686 树转化为数组表示,线段树区间更新

2015-03-14 22:46 375 查看
A Simple Tree Problem

Time Limit: 3 Seconds      Memory Limit: 65536 KB

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.

Sample Input

3 2
1 1
o 2
q 1


Sample Output

1

Author: CUI, Tianyi
Contest: ZOJ Monthly, March 2013

先用dfs对树进行先序遍历并记录下每个节点的位置pos[rt]和它的儿子数tot[rt],这样就将同一棵子树按先序顺序保存在连续的数组区间,然后就转化为线段树求解区间和问题,遍历+区间更新O(n+mlogn)复杂度

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>

using namespace std;

#define maxn 100005

vector<int> g[maxn]; //保存每个节点的儿子
int tot[maxn]; //每个节点的儿子数
int pos[maxn]; //每个节点转为数组后对应的位置
int n, m;

int count(int rt, int &cur) //先序遍历确定位置,并统计儿子数
{
pos[rt] = cur++;
int sum = 1;
for(int i = 0; i < g[rt].size(); i++)
sum += count(g[rt][i], cur);

tot[rt] = sum-1;
return sum;
}

int begin[4*maxn], end[4*maxn], sum[4*maxn];
bool lazy[4*maxn];

void build(int rt, int l, int r)
{
begin[rt] = l; end[rt] = r;
sum[rt] = 0; lazy[rt] = 0;
if(l == r)
return;

int m = (l+r)>>1;
build(2*rt, l, m);
build(2*rt+1,m+1,r);
}

int query(int rt, int ll, int rr)
{
int lc = 2*rt, rc =2*rt+1;
if(ll == begin[rt] && rr == end[rt])
return sum[rt];
else{
if(lazy[rt]){
sum[lc] = end[lc]-begin[lc]+1-sum[lc];
sum[rc] = end[rc]-begin[rc]+1-sum[rc];
lazy[lc] = !lazy[lc];
lazy[rc] = !lazy[rc];
lazy[rt] = 0;
}
}

int m = (begin[rt]+end[rt])>>1;
if(rr <= m)
return query(lc, ll, rr);
else if(ll > m)
return query(rc, ll, rr);
else
return query(lc,ll,m)+query(rc,m+1,rr);
}

void modify(int rt, int ll, int rr)
{
int lc = 2*rt, rc = 2*rt+1;
if(ll == begin[rt] && rr == end[rt]){
sum[rt] = end[rt]-begin[rt]+1-sum[rt];
lazy[rt] = !lazy[rt];
return;
}
else{
if(lazy[rt]){
sum[lc] = end[lc]-begin[lc]+1-sum[lc];
sum[rc] = end[rc]-begin[rc]+1-sum[rc];
lazy[lc] = !lazy[lc];
lazy[rc] = !lazy[rc];
lazy[rt] = 0;
}
}

int m = (end[rt]+begin[rt])>>1;
if(rr <= m)
modify(lc, ll, rr);
else if(ll > m)
modify(rc, ll, rr);
else{
modify(lc, ll, m);
modify(rc, m+1, rr);
}

sum[rt] = sum[lc]+sum[rc];
}

int main()
{
while(~scanf("%d %d", &n, &m)){
for(int i = 0; i <n+2; i++) g[i].clear();
int t;
for(int i = 0; i < n-1; i++){
scanf("%d", &t);
g[t].push_back(i+2);
}

int cur = 1;
count(1,cur);
build(1,1,n);

char op[2];
int num;
for(int i = 0 ; i < m; i++){
scanf("%s %d", op, &num);

if(op[0] == 'o')
modify(1, pos[num], pos[num]+tot[num]);
else
printf("%d\n", query(1, pos[num], pos[num]+tot[num]));
}
printf("\n");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  线段树
相关文章推荐