P3870 [TJOI2009] 开关 题解
思路
一眼线段树板子题。
用线段树来维护每一个区间和更改区间的值。
tag 函数主要是维护儿子的 sum 值。
懒标记在此题中主要指这个区间是否需要更改。
AC代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=1145141;
int ans,n,m,a,b,c;
struct tree {
int l,r,sum,add;
} t[maxn];
void build(int u,int x,int y) {
t[u].l=x;
t[u].r=y;
if(x==y) {
t[u].sum=0;
return ;
}
int mid=(x+y)>>1;
build(u*2,x,mid);
build(u*2+1,mid+1,y);
}//建树
void tag(int u) {
if(t[u].add==0)
return;//如果父亲不动,那儿子也不动
t[u*2].sum=t[u*2].r-t[u*2].l+1-t[u*2].sum;
t[u*2+1].sum=t[u*2+1].r-t[u*2+1].l+1-t[u*2+1].sum;//维护儿子的sum值
if(t[u*2].add==0){
t[u*2].add=1;
}//如果左儿子没有懒标记的话就给他懒标记
else{
t[u*2].add=0;
}
if(t[u*2+1].add==0){
t[u*2+1].add=1;
}
else{
t[u*2+1].add=0;
}//处理右儿子,跟左儿子一样
t[u].add=0;//左右儿子的父亲已经修改过了,所以父亲的懒标记要归0,也就是说父亲不需要改。
}
void change(int u,int l,int r) {
if(l<=t[u].l&&t[u].r<=r) {
t[u].sum=t[u].r-t[u].l+1-t[u].sum;
if(t[u].add==0){
t[u].add=1;
}
else{
t[u].add=0;
}
return ;
}
tag(u);
int mid=(t[u].l+t[u].r)>>1;
if(a<=mid){
change(u*2,l,r);
}
if(b>mid){
change(u*2+1,l,r);
}
t[u].sum=t[u*2].sum+t[u*2+1].sum;
}//改状态
int ask(int u,int l,int r) {
if(l<=t[u].l&&r>=t[u].r){
return t[u].sum;
}
tag(u);
int mid=(t[u].l+t[u].r)/2;
int ans=0;
if(a<=mid){
ans+=ask(u*2,l,r);
}
if(b>mid){
ans+=ask(u*2+1,l,r);
}//二分查
return ans;
}//查询
int main() {
cin>>n>>m;
build(1,1,n);
for(int i=1; i<=m; i++) {
cin>>c>>a>>b;
if(c==0){
change(1,a,b);
}
else{
cout<<ask(1,a,b)<<endl;
}
}
return 0;
}

浙公网安备 33010602011771号