BZOJ 1858【线段树】
题意:
0 a b 把 [a, b] 区间内的所有数全变成0
1 a b 把 [a, b] 区间内的所有数全变成1
2 a b 把 [a,b] 区间内的所有数全部取反
3 a b 询问 [a, b] 区间内总共有多少个1
4 a b 询问 [a, b] 区间内最多有多少个连续的1
思路:
首先 线段树 可以搞个标记 flag 是否都是 1(flag=1)/0(flag=-1) LAZY一下
询问区间有多少个 1 ,那就是求和而已?
询问区间最多有多少个连续的1 ?
主要是区间合并的时候要判断
左儿子的Right_Num ==1 && 右儿子的Left_Num ==1 然后还要算下这段区间,和最大值比较。
0 a b 把 [a, b] 区间内的所有数全变成0
1 a b 把 [a, b] 区间内的所有数全变成1
2 a b 把 [a,b] 区间内的所有数全部取反
3 a b 询问 [a, b] 区间内总共有多少个1
4 a b 询问 [a, b] 区间内最多有多少个连续的1
思路:
首先 线段树 可以搞个标记 flag 是否都是 1(flag=1)/0(flag=-1) LAZY一下
询问区间有多少个 1 ,那就是求和而已?
询问区间最多有多少个连续的1 ?
主要是区间合并的时候要判断
左儿子的Right_Num ==1 && 右儿子的Left_Num ==1 然后还要算下这段区间,和最大值比较。
so,我再搞两个值,一个结点区间的 左端点 连续为 1 的距离,右端点 连续为1 的距离
后面发现还要再添,一个结点区间的 左端点 连续为 0 的距离,右端点 连续为0 的距离,方便反转
现在发现,线段树 就是个 大模拟= =、好像所有的东西都是大模拟。。
#include<bits/stdc++.h> using namespace std; typedef long long LL; const int N=1e5+10; struct Seg{ int Left,Right; int Flag; //标记 int Sum; //区间1的个数 int Max_Len; //区间 连续 1的 最长长度 int Left_Len1,Right_Len1; //区间左端点连续为1的距离,右端点 连续为1 的距离 int Left_Len0,Right_Len0; //区间左端点连续为0的距离,右端点 连续为0 的距离 }q[N*4]; void Pushdown(int num) { if(!q[num].Flag) return; if(q[num].Flag==1) { q[num<<1].Sum=q[num<<1].Left_Len1=q[num<<1].Right_Len1=q[num<<1].Max_Len=(q[num<<1].Right-q[num<<1].Left+1); q[num<<1].Left_Len0=q[num<<1].Right_Len0=0; q[num<<1].Flag=1; q[num<<1|1].Sum=q[num<<1|1].Left_Len1=q[num<<1|1].Right_Len1=q[num<<1|1].Max_Len=(q[num<<1|1].Right-q[num<<1|1].Left+1); q[num<<1|1].Left_Len0=q[num<<1|1].Right_Len0=0; q[num<<1|1].Flag=1; q[num].Flag=0; } else { q[num<<1].Sum=q[num<<1].Left_Len1=q[num<<1].Right_Len1=q[num<<1].Max_Len=0; q[num<<1].Left_Len0=q[num<<1].Right_Len0=(q[num<<1].Right-q[num<<1].Left+1); q[num<<1].Flag=-1; q[num<<1|1].Sum=q[num<<1|1].Left_Len1=q[num<<1|1].Right_Len1=q[num<<1|1].Max_Len=0; q[num<<1|1].Left_Len0=q[num<<1|1].Right_Len0=(q[num<<1|1].Right-q[num<<1|1].Left+1); q[num<<1|1].Flag=-1; q[num].Flag=0; } } void Pushup(int num) { if(q[num].Sum==(q[num].Right-q[num].Left+1)) { q[num].Flag=1; q[num].Left_Len1=q[num].Right_Len1=q[num].Max_Len=q[num].Sum; q[num].Left_Len0=q[num].Right_Len0=0; } else if(!q[num].Sum) { q[num].Flag=-1; q[num].Left_Len1=q[num].Right_Len1=q[num].Max_Len=q[num].Sum; q[num].Left_Len0=q[num].Right_Len0=q[num].Right-q[num].Left+1; } else { q[num].Flag=0; int Max=max(q[num<<1].Max_Len,q[num<<1|1].Max_Len); Max=max(q[num<<1].Right_Len1+q[num<<1|1].Left_Len1,Max); q[num].Max_Len=Max; if(q[num<<1].Left_Len1==(q[num<<1].Right-q[num<<1].Left+1)) { q[num].Left_Len1=q[num<<1].Left_Len1+q[num<<1|1].Left_Len1; q[num].Left_Len0=0; } else { q[num].Left_Len1=q[num<<1].Left_Len1; if(q[num<<1].Left_Len0==(q[num<<1].Right-q[num<<1].Left+1)) q[num].Left_Len0=q[num<<1].Left_Len0+q[num<<1|1].Left_Len0; else q[num].Left_Len0=q[num<<1].Left_Len0; } if(q[num<<1|1].Right_Len1==(q[num<<1|1].Right-q[num<<1|1].Left+1)) { q[num].Right_Len1=q[num<<1].Right_Len1+q[num<<1|1].Right_Len1; q[num].Right_Len0=0; } else { q[num].Right_Len1=q[num<<1|1].Right_Len1; if(q[num<<1|1].Right_Len0==(q[num<<1|1].Right-q[num<<1|1].Left+1)) q[num].Right_Len0=q[num<<1].Right_Len0+q[num<<1|1].Right_Len0; else q[num].Right_Len0=q[num<<1|1].Right_Len0; } } } void Build(int num,int Left,int Right) { q[num].Left=Left;q[num].Right=Right; if(Left==Right) { scanf("%d",&q[num].Sum); if(q[num].Sum==1) q[num].Flag=1; else q[num].Flag=-1; q[num].Left_Len1=q[num].Right_Len1=q[num].Max_Len=q[num].Sum; q[num].Left_Len0=q[num].Right_Len0=1-q[num].Sum; return; } int Mid=(q[num].Left+q[num].Right)>>1; Build(num<<1,Left,Mid); Build(num<<1|1,Mid+1,Right); q[num].Sum=q[num<<1].Sum+q[num<<1|1].Sum; Pushup(num); } void Update1(int num,int Left,int Right) { if(q[num].Left>=Left && q[num].Right<=Right) { q[num].Flag=-1; q[num].Left_Len1=q[num].Right_Len1=q[num].Max_Len=q[num].Sum=0; q[num].Left_Len0=q[num].Right_Len0=q[num].Right-q[num].Left+1; return; } Pushdown(num); int Mid=(q[num].Left+q[num].Right)>>1; if(Mid>=Right) Update1(num<<1,Left,Right); else if(Mid<Left) Update1(num<<1|1,Left,Right); else { Update1(num<<1,Left,Mid); Update1(num<<1|1,Mid+1,Right); } q[num].Sum=q[num<<1].Sum+q[num<<1|1].Sum; Pushup(num); } void Update2(int num,int Left,int Right) { if(q[num].Left>=Left && q[num].Right<=Right) { q[num].Flag=1; q[num].Left_Len1=q[num].Right_Len1=q[num].Max_Len=q[num].Sum=(q[num].Right-q[num].Left+1); q[num].Left_Len0=q[num].Right_Len0=0; return; } Pushdown(num); int Mid=(q[num].Left+q[num].Right)>>1; if(Mid>=Right) Update2(num<<1,Left,Right); else if(Mid<Left) Update2(num<<1|1,Left,Right); else { Update2(num<<1,Left,Mid); Update2(num<<1|1,Mid+1,Right); } q[num].Sum=q[num<<1].Sum+q[num<<1|1].Sum; Pushup(num); } void Update3(int num,int Left,int Right) { if(q[num].Left>=Left && q[num].Right<=Right && (q[num].Sum==0||q[num].Sum==(q[num].Right-q[num].Left+1))) { if(q[num].Sum==(q[num].Right-q[num].Left+1)) q[num].Flag=-1; else q[num].Flag=1; q[num].Max_Len=q[num].Sum=q[num].Right-q[num].Left+1-q[num].Sum; swap(q[num].Right_Len0,q[num].Right_Len1); swap(q[num].Left_Len0,q[num].Left_Len1); return; } Pushdown(num); int Mid=(q[num].Left+q[num].Right)>>1; if(Mid>=Right) Update3(num<<1,Left,Right); else if(Mid<Left) Update3(num<<1|1,Left,Right); else { Update3(num<<1,Left,Mid); Update3(num<<1|1,Mid+1,Right); } q[num].Sum=q[num<<1].Sum+q[num<<1|1].Sum; Pushup(num); } int Query(int num,int Left,int Right) { if(q[num].Left>=Left && q[num].Right<=Right) return q[num].Sum; Pushdown(num); int Mid=(q[num].Left+q[num].Right)>>1; if(Mid>=Right) return Query(num<<1,Left,Right); else if(Mid<Left) return Query(num<<1|1,Left,Right); else return Query(num<<1,Left,Mid)+Query(num<<1|1,Mid+1,Right); } int MaxLen(int num,int Left,int Right) { if(q[num].Left>=Left && q[num].Right<=Right) return q[num].Max_Len; Pushdown(num); int Mid=(q[num].Left+q[num].Right)>>1; if(Mid>=Right) return MaxLen(num<<1,Left,Right); else if(Mid<Left) return MaxLen(num<<1|1,Left,Right); else { int Len1=MaxLen(num<<1,Left,Mid); int Len2=MaxLen(num<<1|1,Mid+1,Right); int Len3=min(q[num<<1].Right_Len1,Mid-Left+1) + min(q[num<<1|1].Left_Len1,Right-Mid); return max(Len1,max(Len2,Len3)); } } int main() { int n,m,x; int Left,Right; scanf("%d%d",&n,&m); Build(1,1,n); while(m--){ scanf("%d%d%d",&x,&Left,&Right); Left++;Right++; switch(x) { case 0: { Update1(1,Left,Right); break;} case 1: { Update2(1,Left,Right); break;} case 2: { Update3(1,Left,Right); break;} case 3: { printf("%d\n",Query(1,Left,Right)); break;} case 4: { printf("%d\n",MaxLen(1,Left,Right)); break;} } } return 0; }