您的位置:首页 > 其它

zoj3686 A Simple Tree Problem

2013-04-03 12:41 281 查看
题意:给定一棵有根树,节点标号为1 ~ n, 根节点固定为1, 每个节点初始值为0。 总共给定M 个操作
操作1:o node 将以node 为根的子树的所有节点的值取反,其实就是一个异或操作
操作2:q node 问以node为跟的子树的所有节点值为1的总数

分析:对做过LCA 转RMQ的应该能想到一点,如果从根节点深搜一遍得到的欧拉序列,仔细观察一下可以发现,每个节点在欧拉序列上其实对应这一个区间,这样就将对子树的操作转移到了对区间的操作。
做完这一步处理之后,熟悉线段树的同学应该就可以解决了,事实上接下来的操作比之前比赛的一道线段树很像。。
线段树的每一个节点保存该节点对应区间上1的个数cnt,如果对该区间做一个异或操作,则该区间1的个数变为cnt = len - cnt (len 为区间长度),,, 这一点还是比较好理解的。
当然,为了提高效率,关于线段树的lazy 操作,还是少不了的。关于lazy操作不理解的话,,可以再单独补一下

zoj3686

#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

using namespace std;

const int N = 100000 + 10;

int spos
,epos
;
int indexx;
bool vis
;

vector<int> g
;

void dfs(int u)
{
spos[u]=indexx;//记录子树的起始位置
vis[u]=true;
for(int i=0;i<g[u].size();i++)
{
int v=g[u][i];
if(!vis[v])
{
indexx++;
dfs(v);
}
}
epos[u]=indexx;//记录子树的终点位置
}

struct Node
{
int l,r;
int c,cnt;
}p[3*N];

void build(int k,int s,int t)
{
int kl, kr, mid;
p[k].l = s; p[k].r = t;p[k].c = 0;
if(s == t) {
p[k].cnt = 0;
return ;
}
mid=(s + t) >> 1; kl = k << 1; kr = kl + 1;
build(kl, s, mid);
build(kr, mid+1, t);
p[k].cnt = p[kl].cnt + p[kr].cnt;
}

void Push_Down(int k, int v)
{
p[k].c ^= v;
p[k].cnt = p[k].r-p[k].l + 1 - p[k].cnt;
}

void insert(int k,int s,int t,int v)
{
if(s <= p[k].l&& t >= p[k].r)
{
Push_Down(k, v);
return ;
}
else {

int mid=(p[k].r + p[k].l) >> 1, kl = k << 1, kr = kl + 1;
if(p[k].c != 0)
{
Push_Down(kl, p[k].c);
Push_Down(kr, p[k].c);
p[k].c = 0;
}
if(s <= mid) insert(kl, s, t, v);
if(t > mid) insert(kr, s, t, v);
p[k].cnt = p[kr].cnt + p[kl].cnt;
}
}

int query(int k,int s,int t)
{
if(s <= p[k].l && t >= p[k].r)
{
return p[k].cnt;
}

int mid=(p[k].r + p[k].l) >> 1,kl = k << 1,kr = kl + 1;

if(p[k].c)
{
Push_Down(kl, p[k].c);
Push_Down(kr, p[k].c);
p[k].c = 0;
}
int a = 0,b = 0;
if(s <= mid) a = query(kl,s,t);
if(t > mid) b = query(kr,s,t);
p[k].cnt = p[kl].cnt + p[kr].cnt;
return a + b;
}

int main()
{
int n, m, a;
while(scanf("%d %d",&n, &m) == 2)
{
for(int i = 1; i <= n; ++i)
g[i].clear();
for(int i = 1; i < n; ++i)
{
scanf("%d",&a);
g[a].push_back(i + 1);
}
indexx = 1;
memset(vis,false,sizeof(vis));
dfs(1);
build(1,1,n);

char op[2];

while(m--)
{
scanf("%s %d",op, &a);
if(op[0] == 'o')
insert(1, spos[a], epos[a], 1);
else printf("%d\n",query(1, spos[a], epos[a]));
}
puts("");
}
return 0;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: