Fork me on GitHub

2014 Super Training #9 F A Simple Tree Problem --DFS+线段树

原题: ZOJ 3686 http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3686

这题本来是一个比较水的线段树,结果一个mark坑了我好几个小时。。哎。太弱。

先DFS这棵树,树形结构转换为线性结构,每个节点有一个第一次遍历的时间和最后一次遍历的时间,之间的时间戳都为子树的时间戳,用线段树更新这段区间即可实现更新子树的效果,用到懒操作节省时间。

坑我的地方: update时,不能写成:tree[rt].mark = 1, 而要写成 tree[rt].mark ^= 1; 因为如果持续update偶数次相当于什么都没做,但是每次update确实是更新了的啊,每次pushdown都会将tree[rt].mark变为0的啊,也就是说tree[rt].mark是不能保持的,所以我搞不懂的是为什么要异或1,而不能直接令等于1,有待向大神请教,如果有看到并知道的仁兄可以指教一下我。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
using namespace std;
#define N 100007

struct node
{
    int l,r;
}p[N];

struct Tree
{
    int sum,mark;
}tree[8*N];
int Time;
vector<int> G[N];

void pushup(int rt)
{
    tree[rt].sum = tree[2*rt].sum + tree[2*rt+1].sum;
}

void build(int l,int r,int rt)
{
    tree[rt].sum = tree[rt].mark = 0;
    if(l == r)
        return;
    int mid = (l+r)/2;
    build(l,mid,2*rt);
    build(mid+1,r,2*rt+1);
    pushup(rt);
}

void pushdown(int l,int r,int rt)
{
    if(!tree[rt].mark)
        return;
    int mid = (l+r)/2;
    tree[2*rt].mark ^= 1;           //not "tree[2*rt].mark = tree[rt].mark"
    tree[2*rt+1].mark ^= 1;
    tree[2*rt].sum = (mid-l+1)-tree[2*rt].sum;
    tree[2*rt+1].sum = (r-mid)-tree[2*rt+1].sum;
    tree[rt].mark = 0;
}

void update(int l,int r,int aa,int bb,int rt)
{
    if(aa<=l && bb>=r)
    {
        tree[rt].mark ^= 1;   //not "tree[rt].mark = 1", 因为偶数次操作相互抵消
        tree[rt].sum = r-l+1-tree[rt].sum;
        return;
    }
    pushdown(l,r,rt);
    int mid = (l+r)/2;
    if(aa <= mid)
        update(l,mid,aa,bb,2*rt);
    if(bb > mid)
        update(mid+1,r,aa,bb,2*rt+1);
    pushup(rt);
}

void dfs(int u)
{
    p[u].l = Time++;
    for(int i=0;i<G[u].size();i++)
        dfs(G[u][i]);
    p[u].r = Time++;
}

int query(int l,int r,int aa,int bb,int rt)
{
    if(aa>r || bb<l)
        return 0;
    if(aa<=l && bb>=r)
        return tree[rt].sum;
    pushdown(l,r,rt);
    int mid = (l+r)/2;
    return query(l,mid,aa,bb,2*rt)+query(mid+1,r,aa,bb,2*rt+1);
}

int main()
{
    int n,m,i,j,x;
    char ss[3];
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        for(i=0;i<=n;i++)
            G[i].clear();
        for(i=2;i<=n;i++)
        {
            scanf("%d",&x);
            G[x].push_back(i);
        }
        Time = 1;
        dfs(1);
        build(1,2*n,1);
        while(m--)
        {
            scanf("%s%d",ss,&x);
            if(ss[0] == 'o')
                update(1,2*n,p[x].l,p[x].r,1);
            else
                printf("%d\n",query(1,2*n,p[x].l,p[x].r,1)/2);
        }
        puts("");
    }
    return 0;
}
View Code

 

posted @ 2014-07-07 21:16  whatbeg  阅读(253)  评论(0编辑  收藏  举报