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

 

你可能感兴趣的:(simple)