• 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;
    
    }
  • 相关阅读:
    leetcode Simplify Path
    leetcode Evaluate Reverse Polish Notation
    leetcode Swap Nodes in Pairs
    leetcode MinStack
    leetcode length of the last word
    empty能否代替isset?
    thinkphp框架的路径
    PHP 反射类的简单使用!
    在windows下配置redis扩展
    phpmyadmin的windows下和linux下的安装。
  • 原文地址:https://www.cnblogs.com/nanke/p/2997661.html
Copyright © 2020-2023  润新知