洛谷P2574 XOR的艺术(线段树)——Chemist

当线段树遇上无敌位运算!

还是老套路,线段树维护区间和,一个区间有几个"1"就是这个区间的区间和,同时支持区间修改区间查询,只不过操作从加法变成了异或。主要难点就在更新懒标记那里,详解见代码:

#include<bits/stdc++.h>
using namespace std; const int MAXX=200010; int read() { int ans=0; char ch=getchar(),last=' '; while(ch>'9'||ch<'0') {last=ch;ch=getchar();} while(ch>='0'&&ch<='9') {ans=ans*10+ch-'0';ch=getchar();} if(last=='-')ans=-ans; return ans; } int n,m,a[MAXX]; char c[MAXX]; struct Segment_Tree{ int l,r,sum,tag; }t[4*MAXX]; void pushup(int p) { t[p].sum=t[p*2].sum+t[p*2+1].sum; //维护区间和,也就是统计区间里有几个"1" } void pushdown(int p)//下放懒标记 { if(t[p].tag){ t[p*2].tag^=1; t[p*2+1].tag^=1; //更新子节点的懒标记 t[p*2].sum=(t[p*2].r-t[p*2].l+1)-t[p*2].sum; //该区间异或1后全部取反,因此"1"的数量等于整个区间长减去原来"1"的数量 t[p*2+1].sum=(t[p*2+1].r-t[p*2+1].l+1)-t[p*2+1].sum; t[p].tag=0; } } void build(int p,int l,int r) { t[p].l=l;t[p].r=r; if(l==r){t[p].sum=a[l];t[p].tag=0;return;} int mid=(l+r)/2; build(p*2,l,mid); build(p*2+1,mid+1,r); pushup(p); } void Xor(int p,int l,int r) { if(l<=t[p].l&&r>=t[p].r) {t[p].sum=(t[p].r-t[p].l+1)-t[p].sum; t[p].tag^=1;return;} pushdown(p); int mid=(t[p].l+t[p].r)/2; if(l<=mid)Xor(p*2,l,r); if(r>mid)Xor(p*2+1,l,r); pushup(p); } int ask(int p,int l,int r) { if(l<=t[p].l&&r>=t[p].r)return t[p].sum; pushdown(p); int mid=(t[p].l+t[p].r)/2; int ans=0; if(l<=mid)ans+=ask(p*2,l,r); if(r>mid)ans+=ask(p*2+1,l,r); return ans; } int main() { n=read();m=read(); cin>>c+1; for(int i=1;i<=n;i++) a[i]=c[i]-'0'; build(1,1,n); for(int i=1;i<=m;i++){ int op,l,r; op=read();l=read();r=read(); if(op==0)Xor(1,l,r); else printf("%d\n",ask(1,l,r)); } return 0; }

转载于:https://www.cnblogs.com/nopartyfoucaodong/p/9374039.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值