线段树较复杂题,涵盖了线段树的大部分操作。
这题节点维护:
ls:左边最长连续1的长度, rs:右边最长连续1的长度 , ms:整个区间的最长连续1的长度 , sum:区间内1的个数 ,mark:操作懒标记
将取反操作单独做一个函数来处理。
具体维护见代码:
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespace std; #define N 100027 struct node { int ls,rs,ms; int sum; int mark; }tree[4*N]; int a[N]; int n,m; void pushup(int l,int r,int rt) { int mid = (l+r)/2; tree[rt].sum = tree[2*rt].sum + tree[2*rt+1].sum; tree[rt].ls = tree[2*rt].ls; if(tree[rt].ls == mid-l+1) tree[rt].ls += tree[2*rt+1].ls; tree[rt].rs = tree[2*rt+1].rs; if(tree[rt].rs == r-mid) tree[rt].rs += tree[2*rt].rs; tree[rt].ms = max(max(tree[2*rt].ms,tree[2*rt+1].ms),tree[2*rt].rs+tree[2*rt+1].ls); } void pushdown(int l,int r,int rt) { int mid = (l+r)/2; if(tree[rt].mark != -1) { tree[2*rt].mark = tree[2*rt+1].mark = tree[rt].mark; tree[2*rt].sum = tree[rt].mark*(mid-l+1); tree[2*rt+1].sum = tree[rt].mark*(r-mid); tree[2*rt].ms = tree[2*rt].ls = tree[2*rt].rs = tree[2*rt].sum; tree[2*rt+1].ms = tree[2*rt+1].ls = tree[2*rt+1].rs = tree[2*rt+1].sum; tree[rt].mark = -1; } } void build(int l,int r,int rt) { if(l == r) { tree[rt].sum = tree[rt].ms = tree[rt].ls = tree[rt].rs = a[l]; tree[rt].mark = a[l]; return; } tree[rt].mark = -1; int mid = (l+r)/2; build(l,mid,2*rt); build(mid+1,r,2*rt+1); pushup(l,r,rt); } void update_1(int l,int r,int aa,int bb,int op,int rt) { if(aa<=l && bb>=r) { if(op == 0) tree[rt].ms = tree[rt].ls = tree[rt].rs = tree[rt].sum = 0; else tree[rt].ms = tree[rt].ls = tree[rt].rs = tree[rt].sum = r-l+1; tree[rt].mark = op; return; } pushdown(l,r,rt); int mid = (l+r)/2; if(aa<=mid) update_1(l,mid,aa,bb,op,2*rt); if(bb>mid) update_1(mid+1,r,aa,bb,op,2*rt+1); pushup(l,r,rt); } void update_2(int l,int r,int aa,int bb,int rt) { if(aa<=l && bb>=r && tree[rt].mark != -1) { tree[rt].mark = abs(tree[rt].mark - 1); if(tree[rt].mark) tree[rt].sum = tree[rt].ms = tree[rt].ls = tree[rt].rs = r-l+1; else tree[rt].sum = tree[rt].ms = tree[rt].ls = tree[rt].rs = 0; return; } pushdown(l,r,rt); int mid =(l+r)/2; if(aa<=mid) update_2(l,mid,aa,bb,2*rt); if(bb>mid) update_2(mid+1,r,aa,bb,2*rt+1); pushup(l,r,rt); } int query_3(int l,int r,int aa,int bb,int rt) { if(aa>r || bb<l) return 0; if(aa<=l && bb>=r) return tree[rt].sum; pushdown(l,r,rt); int mid = (l+r)/2; int res = 0; if(aa<=mid) res += query_3(l,mid,aa,bb,2*rt); if(bb>mid) res += query_3(mid+1,r,aa,bb,2*rt+1); return res; } int query_4(int l,int r,int aa,int bb,int rt) { if(aa<=l && bb>=r) return tree[rt].ms; pushdown(l,r,rt); int mid = (l+r)/2; if(bb<=mid) return query_4(l,mid,aa,bb,2*rt); else if(aa>mid) return query_4(mid+1,r,aa,bb,2*rt+1); else { int Lf = query_4(l,mid,aa,bb,2*rt); int Rt = query_4(mid+1,r,aa,bb,2*rt+1); int tmp = min(tree[2*rt].rs,mid-aa+1) + min(tree[2*rt+1].ls,bb-mid); return max(max(Lf,Rt),tmp); } } int main() { int t,i; int aa,bb,op; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&m); for(i=1;i<=n;i++) scanf("%d",&a[i]); build(1,n,1); for(i=0;i<m;i++) { scanf("%d%d%d",&op,&aa,&bb); aa++;bb++; if(op<2) update_1(1,n,aa,bb,op,1); else if(op == 2) update_2(1,n,aa,bb,1); else if(op == 3) printf("%d\n",query_3(1,n,aa,bb,1)); else printf("%d\n",query_4(1,n,aa,bb,1)); } } return 0; }