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
",res);
            }
        }printf("
");

    }
    return 0;
}


/*
6 5
1 2 1 4 4
o 4
q 4
q 5
q 6
q 1
*/

  

原文地址:https://www.cnblogs.com/chengsheng/p/4682131.html