题目
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)); } }