版权声明:欢迎大家指正错误,有不同观点的欢迎评论,共同进步 https://blog.csdn.net/Sirius_han/article/details/81604156
Black And White
题意:一个01串,两种操作,1 l r:将区间[l, r]中的1变为0, 0变为1; 0 l r :求区间[l, r]中最长的连续为1的子串的长度;
思路:当改变区间[l, r]时,相当于对其进行与0的异或运算,同一区间操作两次相当于没有操作;
在区间[l, r]中,令l_one记录由l向右开始最长连续1,l_zero记录由l向右开始最长连续0, r_one记录由r开始向左最长连续1, r_zero记录由r开始向左最长连续0;m_one记录区间内最长连续1;m_zero记录区间内最长连续0;len记录区间长度;
对于一个父节点fa来说,fa的l_one等于其左孩子的l_one;如果左孩子的l_one等于做孩子的区间长度,那么就可以和右孩子的l_one连接;以此类推就可以得到fa的l_zero, r_one, r_zero;
那么,fa的m_one就等于左右孩子中m_one最大的一个,因为左右孩子进行了区间合并,所以左孩子的r_one与右孩子的l_one可以合并,所以fa的m_one还等于左孩子的r_one+右孩子的l_one;以此类推可以得到fa的m_zero;
每次对区间[l, r]进行操作后,相当于l_one和l_zero交换,r_one和r_zero交换,m_one和m_zero交换;因为1变0,0变1嘛;
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
struct node{
int l, r, len;
int l_one, r_one;
int l_zero, r_zero;
int m_one, m_zero;
int lazy;
}tr[maxn<<2];
void pushup(int m){
tr[m].l_one=tr[m<<1].l_one;
if(tr[m<<1].l_one==tr[m<<1].len) tr[m].l_one+=tr[m<<1|1].l_one;
tr[m].l_zero=tr[m<<1].l_zero;
if(tr[m<<1].l_zero==tr[m<<1].len) tr[m].l_zero+=tr[m<<1|1].l_zero;
tr[m].r_one=tr[m<<1|1].r_one;
if(tr[m<<1|1].r_one==tr[m<<1|1].len) tr[m].r_one+=tr[m<<1].r_one;
tr[m].r_zero=tr[m<<1|1].r_zero;
if(tr[m<<1|1].r_zero==tr[m<<1|1].len) tr[m].r_zero+=tr[m<<1].r_zero;
tr[m].m_one=max(tr[m<<1].m_one, tr[m<<1|1].m_one);
tr[m].m_one=max(tr[m].m_one, tr[m<<1].r_one+tr[m<<1|1].l_one);
tr[m].m_zero=max(tr[m<<1].m_zero, tr[m<<1|1].m_zero);
tr[m].m_zero=max(tr[m].m_zero, tr[m<<1].r_zero+tr[m<<1|1].l_zero);
}
void pushdown(int m){
if(tr[m].lazy){
tr[m<<1].lazy^=1;
tr[m<<1|1].lazy^=1;
swap(tr[m<<1].m_one, tr[m<<1].m_zero);
swap(tr[m<<1].l_one, tr[m<<1].l_zero);
swap(tr[m<<1].r_one, tr[m<<1].r_zero);
swap(tr[m<<1|1].m_one, tr[m<<1|1].m_zero);
swap(tr[m<<1|1].l_one, tr[m<<1|1].l_zero);
swap(tr[m<<1|1].r_one, tr[m<<1|1].r_zero);
tr[m].lazy=0;
}
}
void build(int m, int l, int r){
tr[m].l=l;
tr[m].r=r;
tr[m].lazy=0;
tr[m].len=r-l+1;
if(l==r){
int x;
scanf("%d", &x);
if(x){
tr[m].l_one=tr[m].r_one=tr[m].m_one=1;
tr[m].l_zero=tr[m].r_zero=tr[m].m_zero=0;
}
else{
tr[m].l_one=tr[m].r_one=tr[m].m_one=0;
tr[m].l_zero=tr[m].r_zero=tr[m].m_zero=1;
}
return;
}
int mid=(l+r)>>1;
build(m<<1, l, mid);
build(m<<1|1, mid+1, r);
pushup(m);
}
void updata(int m, int l, int r){
if(tr[m].l==l&&tr[m].r==r){
swap(tr[m].l_one, tr[m].l_zero);
swap(tr[m].r_one, tr[m].r_zero);
swap(tr[m].m_one, tr[m].m_zero);
tr[m].lazy^=1;//这里是异或,因为连续操作偶数次相当于没有操作;
return;
}
pushdown(m);
int mid=(tr[m].l+tr[m].r)>>1;
if(r<=mid) updata(m<<1, l, r);
else if(l>mid) updata(m<<1|1, l, r);
else{
updata(m<<1, l, mid);
updata(m<<1|1, mid+1, r);
}
pushup(m);
}
int query(int m, int l, int r){
if(tr[m].l==l&&tr[m].r==r){
return tr[m].m_one;
}
pushdown(m);
int mid=(tr[m].l+tr[m].r)>>1;
int temp;
if(r<=mid) temp=query(m<<1, l, r);
else if(l>mid) temp=query(m<<1|1, l, r);
else{
int lmax=query(m<<1, l, mid);
int rmax=query(m<<1|1, mid+1, r);
int mm=min(tr[m<<1].r_one, mid-l+1)+min(tr[m<<1|1].l_one, r-mid);
temp=max(max(lmax, rmax), mm);
}
pushup(m);
return temp;
}
int main(){
int n, m, op, l, r;
while(~scanf("%d", &n)){
build(1, 1, n);
scanf("%d", &m);
while(m--){
scanf("%d%d%d", &op, &l, &r);
if(op){
updata(1, l, r);
}
else printf("%d\n", query(1, l, r));
}
}
return 0;
}