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
Sample Output
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;
}
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;
}
相关文章推荐
- ZOJ 3686 A Simple Tree Problem(树转线段树+线段树区间更新)
- ZOJ 3686 A Simple Tree Problem(将对树的操作转化成区间=>线段树)
- HDU 1556 Color the ball 很典型的更新区间查找点的题(线段树树状数组两种解法)
- poj-3468 线段树和树状数组的区间更新及求和
- ZOJ 2706 Thermal Death of the Universe(线段树区间更新)
- BNU 28887——A Simple Tree Problem——————【将多子树转化成线段树+区间更新】
- zoj 1610 Count the Colors 线段树区间更新/暴力
- HDU 1556 Color the ball (线段树|树状数组,区间更新)
- HDOJ-1556(线段树||树状数组,区间更新+点查询)
- zoj 2706 Thermal Death of the Universe (线段树区间更新,区间求和)
- ZOJ 1610 Count the Colors (线段树区间更新)
- Zoj 1610 Count the Colors (线段树+区间更新+暴力计数)
- zoj 3686 简单线段树更新 好久没写这个东东了!!!
- POJ 2155 Matrix (二维线段树入门,成段更新,单点查询 / 二维树状数组,区间更新,单点查询)
- ZOJ 1610 Count the Colors(线段树区间更新)
- zoj 3633 线段树单点更新 区间最大值
- poj 3468 A Simple Problem with Integers(线段树区间更新 or 树状数组区间更新)
- ZOJ 3632 Watermelon Full of Water (线段树 区间更新 + dp)
- hdu1556 color the ball 树状数组区间更新单点查询(附线段树做法)与二维扩展
- hdoj 1556 Color the ball 【线段树 + lazy区间更新】 【树状数组】