BNU 28887——A Simple Tree Problem——————【将多子树转化成线段树+区间更新】

A Simple Tree Problem

Time Limit: 3000ms
Memory Limit: 65536KB
This problem will be judged on  ZJU. Original ID: 3686
64-bit integer IO format: %lld      Java class name: Main
Type: 
None
 
 

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

 

题目大意:有棵根节点为1的树,共有n个节点。有m次询问。第二行为从2--->n各个节点对应的父亲节点编号。下面的m行是询问,o  ai表示将节点为ai的子树所有节点的值进行异或即0变1,1变0。q ai表示询问目前该子树的节点的和值为多少。

 

解题思路:其实这个题目重点在如何将多子树转化成线段树进行操作。我们如果重新将树编号,那么可以让每个节点对应一段区间。从根节点1开始深搜,编号为1,每当搜到一个节点,就让编号的值加1,让这个编号等于该节点的区间左端点,等把该节点的所有子节点访问完后,将这时的编号赋值给该节点的区间右端点。这时这个区间内的所有节点都是该节点的子节点。  后边就是区间更新的问题了。

 

#include<bits/stdc++.h>

using namespace std;

#define mid (L+R)/2

#define lson rt*2,L,mid

#define rson rt*2+1,mid+1,R

const int maxn=1e5+50;

vector<int>G[maxn];

int Lt[maxn],Rt[maxn];

int sumv[maxn*4],lazy[maxn*4];

int n,cn;

void dfs(int u){

    Lt[u]=++cn;

    int v;

    for(int i=0;i<G[u].size();i++){

        v=G[u][i];

        dfs(v);

    }

    Rt[u]=cn;

}

void build(int rt,int L,int R){

    sumv[rt]=lazy[rt]=0;

    if(L==R)

        return ;

    build(lson);

    build(rson);

}

void PushDown(int rt,int L,int R){

    if(lazy[rt]){

        lazy[rt*2]^=1;

        lazy[rt*2+1]^=1;

        sumv[rt*2]=(mid-L+1)-sumv[rt*2];    

        sumv[rt*2+1]=(R-mid)-sumv[rt*2+1];  

        lazy[rt]=0;

    }

}

void PushUp(int rt){

    sumv[rt]=sumv[rt*2]+sumv[rt*2+1];

}

void update(int rt,int L,int R,int l_ran,int r_ran){

    if(l_ran<=L&&R<=r_ran){

        lazy[rt]^=1;

        sumv[rt]=R-L+1-sumv[rt];

        return ;

    }

    PushDown(rt,L,R);

    if(l_ran<=mid){

        update(lson,l_ran,r_ran);

    }

    if(r_ran>mid){

        update(rson,l_ran,r_ran);

    }

    PushUp(rt);

}

int query(int rt,int L,int R,int l_ran,int r_ran){

    if(l_ran<=L&&R<=r_ran){

        return sumv[rt];

    }

    int ret=0;

    PushDown(rt,L,R); //lazy下放

    if(l_ran<=mid){

        ret+=query(lson,l_ran,r_ran);

    }

    if(r_ran>mid){

        ret+=query(rson,l_ran,r_ran);

    }

    return ret;

}

int main(){

    char s[4];

    int m,subt,a,res;

    while(scanf("%d%d",&n,&m)!=EOF){

        build(1,1,n);

        for(int i=0;i<=n;i++)

            G[i].clear();

        for(int i=2;i<=n;i++){

            scanf("%d",&a);

            G[a].push_back(i);

        }

        cn=0;

        dfs(1);

        for(int i=0;i<m;i++){

            scanf("%s%d",s,&subt);

            if(s[0]=='o'){

                update(1,1,n,Lt[subt],Rt[subt]);

            }else{

                res=query(1,1,n,Lt[subt],Rt[subt]);

                printf("%d\n",res);

            }

        }printf("\n");



    }

    return 0;

}





/*

6 5

1 2 1 4 4

o 4

q 4

q 5

q 6

q 1

*/

  

你可能感兴趣的:(simple)