zoukankan      html  css  js  c++  java
  • 线段树 P2574 【区间修改 区间查询】

    题目

    https://www.luogu.com.cn/problem/P2574

    题目分析

    1.伤害为伤害串的这个范围内中字符 1 的个数:求伤害就是简单的区间查询
    2.会修改伤害串中的数值,修改的方法是把原来的字符0变1,1变0:区间修改
    3.因为求伤害就是简单的区间和,又是区间修改与区间查询,所以使用区间和形式的线段树,叶子节点表示伤害串的每一位,非叶子节点用来求和。
    4.节点有两个属性,一个是1的个数,一个是0的个数,这样设计目的是非叶子节点在求和的时候,由于自己的子节点全部要0变1,1变0,
    所以并不知道总和怎么变,而这样设计属性的话,只需要swap(c[k].one, c[k].zero); 然后统计伤害值时只看c[k].one(1的个数)即可。
    5.关于lazy【】数组的设计就是使用了异或方式,开始lazy【】为0,表示1的个数与0的个数不用交换,一旦发生修改,
    就在update中把自己节点c【k】的1的个数与0的个数交换,并将lazy【k】与自己异或(这样原来是1现在就是0,原来是0现在就是1),告诉自己的子节点也要进行交换。

    代码

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    #define MAX 2000105
    struct node
    {
        long long zero;
        long long one;
    }c[MAX << 2];
    char a[MAX];int lazy[MAX<<2];
    int n, m;
    void build(int l,int r,int k)
    {
        if (l == r)
        {
            if (a[l] == '1')c[k].one=1;
            else c[k].zero=1;   
        }
        else
        {
            int mid = (l + r) >> 1;
            build(l, mid, k << 1);
            build(mid + 1, r, k << 1 | 1);
            c[k].one = c[k << 1].one + c[k<<1|1].one;
            c[k].zero = c[k << 1].zero + c[k << 1 | 1].zero;
        }   
    }
    void pushdown(int l,int r,int k)
    {
        if (lazy[k])
        {
            lazy[k << 1] ^= 1;
            lazy[k << 1|1] ^= 1;
            swap(c[k << 1].one,c[k<<1].zero);
            swap(c[k << 1 | 1].one, c[k << 1 | 1].zero);
            if(c[k<<1].one+c[k<<1].zero&&c[k<<1|1].one+c[k<<1|1].zero)
            c[k].one = c[k << 1].one + c[k << 1 | 1].one,
            c[k].zero = c[k << 1].zero + c[k << 1 | 1].zero;
            lazy[k] = 0;
        }
    }
    void update(int L,int R,int l,int r,int k)
    {
        if (L <= l&&R >= r)
        {
            swap(c[k].one, c[k].zero);
            lazy[k] ^= 1;
            pushdown(l,r,k);
        }
        else
        {
            pushdown(l, r, k);
            int mid = (l + r) >> 1;
            if (L <= mid)
                update(L, R, l, mid, k << 1);
            if (R > mid)
                update(L, R, mid + 1, r, k << 1 | 1);
            if(c[k<<1].one+c[k<<1].zero&&c[k<<1|1].one+c[k<<1|1].zero)
            c[k].one = c[k << 1].one + c[k << 1 | 1].one,
            c[k].zero = c[k << 1].zero + c[k << 1 | 1].zero;
        }
    }
    long long query(int L, int R, int l, int r, int k)
    {
        if (L <= l&&R >= r)
        {
            return c[k].one;
        }
        else
        {
            long long res = 0;
            pushdown(l, r, k);
            if(c[k<<1].one+c[k<<1|1].zero&&c[k<<1|1].one+c[k<<1|1].zero)
            c[k].one = c[k << 1].one + c[k << 1 | 1].one,
            c[k].zero = c[k << 1].zero + c[k << 1 | 1].zero;
            int mid = (l + r) >> 1;
            if (L <= mid)res = res + query(L, R, l, mid, k << 1);
            if (R > mid)res = res + query(L, R, mid + 1, r, k << 1 | 1);
            if(c[k<<1].one+c[k<<1].zero&&c[k<<1|1].one+c[k<<1|1].zero)
            c[k].one = c[k << 1].one + c[k << 1 | 1].one,
            c[k].zero = c[k << 1].zero + c[k << 1 | 1].zero;
            return res;
        }
    
    }
    int main()
    {
        int aa, bb, cc;
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= n; i++)
        {
          cin>>a[i];
        }
        build(1, n, 1);
        for (int i = 0; i < m; i++)
        {
            scanf("%d %d %d", &aa, &bb, &cc);
            if (aa == 0)update(bb, cc, 1, n, 1);
            else printf("%lld
    ", query(bb, cc, 1, n, 1));
        }
    
    }
  • 相关阅读:
    sql
    Java 反射
    Java 泛型
    Java 数组小记
    Java 实现二叉树
    Maven的环境配置
    用于解决easui 保存时候,前台传参是空字符串不null
    SpringMVC
    SpringMVC
    解决MySql varchar类型的数字排序
  • 原文地址:https://www.cnblogs.com/Jason66661010/p/12826764.html
Copyright © 2011-2022 走看看