P2572 [SCOI2010]序列操作 线段树

  

题目描述

lxhgww最近收到了一个01序列,序列里面包含了n个数,这些数要么是0,要么是1,现在对于这个序列有五种变换操作和询问操作:

0 a b 把[a, b]区间内的所有数全变成0

1 a b 把[a, b]区间内的所有数全变成1

2 a b 把[a,b]区间内的所有数全部取反,也就是说把所有的0变成1,把所有的1变成0

3 a b 询问[a, b]区间内总共有多少个1

4 a b 询问[a, b]区间内最多有多少个连续的1

对于每一种询问操作,lxhgww都需要给出回答,聪明的程序员们,你们能帮助他吗?

输入输出格式

输入格式:

输入数据第一行包括2个数,n和m,分别表示序列的长度和操作数目

第二行包括n个数,表示序列的初始状态

接下来m行,每行3个数,op, a, b,(0<=op<=4,0<=a<=b<n)表示对于区间[a, b]执行标号为op的操作

输出格式:

对于每一个询问操作,输出一行,包括1个数,表示其对应的答案

输入输出样例

输入样例#1: 复制
10 10
0 0 0 1 1 0 1 0 1 1
1 0 2
3 0 5
2 2 2
4 0 4
0 3 6
2 3 7
4 2 8
1 0 5

题目描述

lxhgww最近收到了一个01序列,序列里面包含了n个数,这些数要么是0,要么是1,现在对于这个序列有五种变换操作和询问操作:

0 a b 把[a, b]区间内的所有数全变成0

1 a b 把[a, b]区间内的所有数全变成1

2 a b 把[a,b]区间内的所有数全部取反,也就是说把所有的0变成1,把所有的1变成0

3 a b 询问[a, b]区间内总共有多少个1

4 a b 询问[a, b]区间内最多有多少个连续的1

对于每一种询问操作,lxhgww都需要给出回答,聪明的程序员们,你们能帮助他吗?

输入输出格式

输入格式:

输入数据第一行包括2个数,n和m,分别表示序列的长度和操作数目

第二行包括n个数,表示序列的初始状态

接下来m行,每行3个数,op, a, b,(0<=op<=4,0<=a<=b<n)表示对于区间[a, b]执行标号为op的操作

输出格式:

对于每一个询问操作,输出一行,包括1个数,表示其对应的答案

输入输出样例

输入样例#1: 复制
10 10
0 0 0 1 1 0 1 0 1 1
1 0 2
3 0 5
2 2 2
4 0 4
0 3 6
2 3 7
4 2 8
1 0 5
0 5 6
3 3 9
输出样例#1: 复制
5
2
6
5


这些操作都比较简单 之前都学过
但是加在一起就会产生一个问题 那就是翻转标记和区间修改标记的顺序该如何处理 先反转和先修改的操作是不一样的


修改操作的优先级是比翻转操作的优先级高的

在update里
对一个点先后两次操作一共有四种方法
1.先反转后修改
显然 翻转的操作已经被覆盖掉了 所以在设置修改懒标记的时候如果有翻转标记直接清空掉

2.先修改后翻转
正常处理

3.4没有问题

在down里
先处理修改的 因为修改的优先级高(先反转后修改的操作已经被覆盖掉了 也就是反转标记已经被清零)
下推懒标记的时候如果下面的两个儿子有翻转标记的话要清空
然后处理翻转标记即可


非常好的线段树 加深了理解
#include<bits/stdc++.h>
using namespace std;
//input by bxd
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define repp(i,a,b) for(int i=(a);i>=(b);--i)
#define RI(n) scanf("%d",&(n))
#define RII(n,m) scanf("%d%d",&n,&m)
#define RIII(n,m,k) scanf("%d%d%d",&n,&m,&k)
#define RS(s) scanf("%s",s)
#define ll long long
#define see(x) (cerr<<(#x)<<'='<<(x)<<endl)
#define pb push_back
#define inf 0x3f3f3f3f
#define lson l,m,pos<<1
#define rson m+1,r,pos<<1|1
#define CLR(A,v)  memset(A,v,sizeof A)
typedef pair<int,int>pii;
//////////////////////////////////
const int N=1e5+10;
int tsum[N<<2],t0[N<<2],t1[N<<2],ri0[N<<2],ri1[N<<2],le0[N<<2],le1[N<<2],len[N<<2],col[N<<2],rev[N<<2];
int num[N];
void up(int pos)
{
    tsum[pos]=tsum[pos<<1]+tsum[pos<<1|1];// 区间求和
    t0[pos]=max( max(t0[pos<<1],t0[pos<<1|1]),ri0[pos<<1]+le0[pos<<1|1]  );
    t1[pos]=max( max(t1[pos<<1],t1[pos<<1|1]),ri1[pos<<1]+le1[pos<<1|1]  );

    if(le1[pos<<1]==len[pos<<1])
    le1[pos]=le1[pos<<1]+le1[pos<<1|1];
    else le1[pos]=le1[pos<<1];

    if(le0[pos<<1]==len[pos<<1])
    le0[pos]=le0[pos<<1]+le0[pos<<1|1];
    else le0[pos]=le0[pos<<1];

    if(ri1[pos<<1|1]==len[pos<<1|1])
    ri1[pos]=ri1[pos<<1|1]+ri1[pos<<1];
    else ri1[pos]=ri1[pos<<1|1];

    if(ri0[pos<<1|1]==len[pos<<1|1])
    ri0[pos]=ri0[pos<<1|1]+ri0[pos<<1];
    else ri0[pos]=ri0[pos<<1|1];
}
void build(int l,int r,int pos)
{
    len[pos]=r-l+1;
    if(l==r){ tsum[pos]=num[l]; le0[pos]=ri0[pos]=t0[pos]=(num[l]==0);  le1[pos]=ri1[pos]=t1[pos]=(num[l]==1); return ;}
    int m=(l+r)>>1;build(lson);build(rson);up(pos);
}
void down(int m,int pos)
{
    if(col[pos]!=-1)// 修改会覆盖翻转
    {
        rev[pos<<1]=rev[pos<<1|1]=0;//覆盖翻转
        col[pos<<1]=col[pos<<1|1]=col[pos];//标记传递

        if(col[pos]==1){
        t1[pos<<1]=tsum[pos<<1]=le1[pos<<1]=ri1[pos<<1]=len[pos<<1];
        t1[pos<<1|1]=tsum[pos<<1|1]=le1[pos<<1|1]=ri1[pos<<1|1]=len[pos<<1|1];
        t0[pos<<1]=t0[pos<<1|1]=le0[pos<<1]=le0[pos<<1|1]=ri0[pos<<1]=ri0[pos<<1|1]=0;}
        else if(col[pos]==0){
        t0[pos<<1]=le0[pos<<1]=ri0[pos<<1]=len[pos<<1];
        t0[pos<<1|1]=le0[pos<<1|1]=ri0[pos<<1|1]=len[pos<<1|1];
        tsum[pos<<1]=tsum[pos<<1|1]=le1[pos<<1]=le1[pos<<1|1]=ri1[pos<<1]=ri1[pos<<1|1]=t1[pos<<1]=t1[pos<<1|1]=0;}
        
        col[pos]=-1;
    }
    if(rev[pos])
    {
        tsum[pos<<1]=len[pos<<1]-tsum[pos<<1];
        tsum[pos<<1|1]=len[pos<<1|1]-tsum[pos<<1|1];

        swap(le1[pos<<1],le0[pos<<1]);
        swap(le1[pos<<1|1],le0[pos<<1|1]);
        swap(ri1[pos<<1],ri0[pos<<1]);
        swap(ri1[pos<<1|1],ri0[pos<<1|1]);
        swap(t1[pos<<1],t0[pos<<1]);
        swap(t1[pos<<1|1],t0[pos<<1|1]);//翻转01最大连续长度

        rev[pos<<1]^=1;rev[pos<<1|1]^=1;
        rev[pos]=0;
    }
}
void upsum(int L,int R,int v,int l,int r,int pos)
{
    if(L<=l&&r<=R)
    {
        col[pos]=v;rev[pos]=0;tsum[pos]=v*(r-l+1);
        t1[pos]=le1[pos]=ri1[pos]=v*(r-l+1);
        t0[pos]=le0[pos]=ri0[pos]=(v^1)*(r-l+1);
        return ;
    }int m=(l+r)>>1;down(r-l+1,pos);
    if(L<=m)upsum(L,R,v,lson);if(R>m)upsum(L,R,v,rson);up(pos);
}
void uprev(int L,int R,int l,int r,int pos)
{
    if(L<=l&&r<=R)
    {
        rev[pos]^=1;
        tsum[pos]=r-l+1-tsum[pos];
        swap(t1[pos],t0[pos]);
        swap(le1[pos],le0[pos]);
        swap(ri1[pos],ri0[pos]);
        return ;
    }int m=(l+r)>>1;down(r-l+1,pos);
    if(L<=m)uprev(L,R,lson);if(R>m)uprev(L,R,rson);up(pos);
}
int qsum(int L,int R,int l,int r,int pos)
{
    if(L<=l&&r<=R)return tsum[pos];
    int ans=0;int m=(l+r)>>1;down(r-l+1,pos);
    if(L<=m)ans+=qsum(L,R,lson);if(R>m)ans+=qsum(L,R,rson);
    return ans;
}
int qmax(int L,int R,int l,int r,int pos)
{
    if(L<=l&&r<=R)return t1[pos];
    int m=(l+r)>>1;
    down(r-l+1,pos);

    if(L<=m&&R>m)
    {
        int ans=max(qmax(L,R,lson),qmax(L,R,rson)),rm,lm;
        rm=min((m-L+1),ri1[pos<<1] );
        lm=min((R-m),le1[pos<<1|1]);
        ans=max(ans,rm+lm);return ans;
    }
    else if(L<=m)return qmax(L,R,lson);
    else if(R>m)return qmax(L,R,rson);
}
int n,m,a,b,c;
int main()
{
    CLR(col,-1);
    RII(n,m);
    rep(i,1,n)RI(num[i]);

    build(1,n,1);
    while(m--)
    {
        RIII(c,a,b);a++,b++;
        if(c==0)upsum(a,b,0,1,n,1);
        if(c==1)upsum(a,b,1,1,n,1);
        if(c==2)uprev(a,b,1,n,1);
        if(c==3)printf("%d
",qsum(a,b,1,n,1));
        if(c==4)printf("%d
",qmax(a,b,1,n,1));
    }
    return 0;
}
View Code








































0 5 6 3 3 9
输出样例#1: 复制
5
2
6
5








原文地址:https://www.cnblogs.com/bxd123/p/11201267.html