链接:https://ac.nowcoder.com/acm/contest/925/K
来源:牛客网
题目描述
公元2019年6月22日,白山茶王国与红玫瑰王国展开大战,在世外仙境——天空花园处,双方军团一字排开,在维持一字长蛇阵的队形下双方战士陷入混战。
然而,为了操控整个战局,白山茶公主与红玫瑰女巫都会一种AOE魔法,使得受到魔法波及的战士"叛变"(白山茶战士变为红玫瑰战士,红玫瑰战士变为白山茶战士)。
可见,这场战争永远没有绝对的优劣势,局势瞬息万变。现在,白山茶公主邀请你协助她了解各个区块的战况。
输入描述:
第一行一个整数n( 0 < n <= 105),表示白山茶战士和红玫瑰战士的数量和。
第二行n个只包含0、1的整数,为一字长蛇阵中的战士类别(1为白山茶战士,0为红玫瑰战士,下标从1开始)。
第三行一个整数m(0 < m <= 100001),表示施放魔法和询问战况的操作次数。
随后m行,每行三个整数op,x,y: (op∈∈ {0,1};1 <= x <= y <= n )
对于op=1,表示对下标属于闭区间[x,y]的战士施放魔法,使她们"叛变";
对于op=0,表示询问下标属于闭区间[x,y]的连续最多的白山茶战士的数目。
输出描述:
对于每一次op=0的操作,输出区间内连续最多的白山茶战士数目。
示例1
说明
0 1 4 : answer=1
1 2 3 : 1 1 0 0
0 1 4 : answer=2
1 3 3 : 1 1 1 0
0 4 4 : answer=0
题意:首先有一个序列,只有 0 和 1组成,有两种操作
1:把区间内的所有值全部翻转,0变1,1变0
0:输出区间内最长的连续1
思路:这一看就是经典的线段树问题
1,首先解决翻转问题,我们只要记录区间内有多少个0,有多少个1,然后我们翻转的时候交换两个值即可
2,输出最长的连续1,这个我们就要记录三个值,前缀最长连续1,后缀最长连续1,然后合并的时候就是左子树的最长连续1和右子树的最长连续1,或者是左子树
后缀+右子树前缀,这个就能得到了,这里为了我们考虑翻转问题,所有我们还要同时记录前缀0和后缀0,这样后面也是找出交换
然后就是些细节问题了,注意查询的时候我们如果涉及两个区间我们要考虑左子树的最长连续1,右子树的最长连续1,左子树的后缀1+右子树的前缀1三个的最大值
还有push_up的时候,前缀1和后缀1要考虑满树的情况
例如 左子树前缀1如果满了的话,就要加上右子树的前缀才是父亲节点的前缀
#include<bits/stdc++.h> #define mod 1000000007 #define pi acos(-1) #define eps 1e-9 using namespace std; typedef long long ll; const int maxn = 100005; struct sss { ll l,r; ll z1,y1; ll z0,y0; ll mx1,mx0; ll cnt; }tree[4*maxn]; ll n,a[maxn]; void push_up(ll rt){ int mid=tree[rt].l+tree[rt].r>>1; tree[rt].mx0=max(tree[rt<<1].mx0,tree[rt<<1|1].mx0); tree[rt].mx0=max(tree[rt].mx0,tree[rt<<1].y0+tree[rt<<1|1].z0); tree[rt].mx1=max(tree[rt<<1].mx1,tree[rt<<1|1].mx1); tree[rt].mx1=max(tree[rt].mx1,tree[rt<<1].y1+tree[rt<<1|1].z1); tree[rt].z0=tree[rt<<1].z0; if(tree[rt].z0==mid-tree[rt].l+1) tree[rt].z0+=tree[rt<<1|1].z0; tree[rt].y0=tree[rt<<1|1].y0; if(tree[rt].y0==tree[rt].r-mid) tree[rt].y0+=tree[rt<<1].y0; tree[rt].z1=tree[rt<<1].z1; if(tree[rt].z1==mid-tree[rt].l+1) tree[rt].z1+=tree[rt<<1|1].z1; tree[rt].y1=tree[rt<<1|1].y1; if(tree[rt].y1==tree[rt].r-mid) tree[rt].y1+=tree[rt<<1].y1; } void build(ll cnt,ll l,ll r){ tree[cnt].l=l; tree[cnt].r=r; if(l==r){ if(a[l]==0){ tree[cnt].z0=1; tree[cnt].y0=1; tree[cnt].mx0=1; } else{ tree[cnt].mx1=1; tree[cnt].z1=1; tree[cnt].y1=1; } return; } ll mid=(l+r)/2; build(cnt*2,l,mid); build(cnt*2+1,mid+1,r); push_up(cnt); } void change(ll cnt){ tree[cnt].cnt++; ll t=tree[cnt].z0; tree[cnt].z0=tree[cnt].z1; tree[cnt].z1=t; t=tree[cnt].y0; tree[cnt].y0=tree[cnt].y1; tree[cnt].y1=t; t=tree[cnt].mx0; tree[cnt].mx0=tree[cnt].mx1; tree[cnt].mx1=t; } void push_down(ll cnt){ tree[cnt].cnt--; change(cnt*2); change(cnt*2+1); } ll query(ll cnt,ll l,ll r){ if(l<=tree[cnt].l&&r>=tree[cnt].r){ return tree[cnt].mx1; } if(tree[cnt].cnt%2) push_down(cnt); ll mid=(tree[cnt].l+tree[cnt].r)/2; if(r<=mid){ return query(cnt*2,l,r); } else if(l>mid){ return query(cnt*2+1,l,r); } else{ ll x=query(cnt*2,l,mid); ll y=query(cnt*2+1,mid+1,r); ll rlv=min(mid-l+1,tree[cnt<<1].y1)+min(r-mid,tree[cnt<<1|1].z1); return max(x,max(y,rlv)); } } void update(ll cnt,ll l,ll r){ if(tree[cnt].l==l&&tree[cnt].r==r){ change(cnt); return; } ll mid=(tree[cnt].l+tree[cnt].r)/2; if(tree[cnt].cnt%2) push_down(cnt); if(r<=mid) update(cnt*2,l,r); else if(l>mid) update(cnt*2+1,l,r); else{ update(cnt*2,l,mid); update(cnt*2+1,mid+1,r); } push_up(cnt); } int main() { cin>>n; for(int i=1;i<=n;i++) cin>>a[i]; ll m,op,l,r; build(1,1,n); cin>>m; for(int i=1;i<=m;i++){ cin>>op>>l>>r; if(op==0){ cout<<query(1,l,r)<<" "; } else{ update(1,l,r); } } }