zoj3686 A Simple Tree Problem

题意:给定一棵有根树,节点标号为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[N],epos[N];
int indexx;
bool vis[N];

vector<int> g[N];

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;

}

 

posted @ 2013-04-03 12:41  枕边梦  阅读(183)  评论(0编辑  收藏  举报