线段树 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));
    }

}
原文地址:https://www.cnblogs.com/Jason66661010/p/12826764.html