洛谷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; }

猜你喜欢

转载自www.cnblogs.com/nopartyfoucaodong/p/9374039.html