洛谷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
   0 5 6
   3 3 9
输出样例#1: 
5
2
6
5

说明

对于30%的数据,1<=n, m<=1000

对于100%的数据,1<=n, m<=100000

看到 区间修改+区间查询。。。

去吧,线段树。。。

于是一个晚上就没了。。。

恶心啊。。。

线段树记录:

区间和值;

区间最长0、1的长度;

从左端点开始最长0、1的长度,葱油断电开始最长0、1的长度;

两个标记:全赋0/1,取反;

左右端点。

3很好做,4呢?

所以求4时,返回的不是一个值,而是一个线段树节点。

修改时,若正在改某区间的 全赋0/1 标记,记得将 取反 标记清0,巨坑。。。

还有上传,下传很重要,但是太恶心,不想多说,看代码吧。。。

附代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#define LSON rt<<1
#define RSON rt<<1|1
#define DATA(x) a[x].data
#define SIGN1(x) a[x].c
#define SIGN2(x) a[x].v
#define SUM1(x) a[x].sum1
#define SUM2(x) a[x].sum2
#define LEFT1(x) a[x].left1
#define LEFT2(x) a[x].left2
#define RIGHT1(x) a[x].right1
#define RIGHT2(x) a[x].right2
#define LSIDE(x) a[x].l
#define RSIDE(x) a[x].r
#define WIDTH(x) (RSIDE(x)-LSIDE(x)+1)
#define MAXN 100010
using namespace std;
int n,m;
struct node{
    int data,c,v,left1,right1,sum1,left2,right2,sum2;
    int l,r;
}a[MAXN<<2];
inline int read(){
	int date=0,w=1;char c=0;
	while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
	while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
	return date*w;
}
void pushup(int rt){
    DATA(rt)=DATA(LSON)+DATA(RSON);
    SUM1(rt)=max(RIGHT1(LSON)+LEFT1(RSON),max(SUM1(LSON),SUM1(RSON)));
    SUM2(rt)=max(RIGHT2(LSON)+LEFT2(RSON),max(SUM2(LSON),SUM2(RSON)));
    LEFT1(rt)=LEFT1(LSON);RIGHT1(rt)=RIGHT1(RSON);
	LEFT2(rt)=LEFT2(LSON);RIGHT2(rt)=RIGHT2(RSON);
    if(LEFT1(LSON)==WIDTH(LSON))LEFT1(rt)+=LEFT1(RSON);
    if(LEFT2(LSON)==WIDTH(LSON))LEFT2(rt)+=LEFT2(RSON);
    if(RIGHT1(RSON)==WIDTH(RSON))RIGHT1(rt)+=RIGHT1(LSON);
    if(RIGHT2(RSON)==WIDTH(RSON))RIGHT2(rt)+=RIGHT2(LSON);
}
void pushdown(int rt){
    if(LSIDE(rt)==RSIDE(rt))return;
    if(SIGN1(rt)!=-1){
        SIGN1(LSON)=SIGN1(rt);
		SIGN2(LSON)=0;
        DATA(LSON)=SUM2(LSON)=LEFT2(LSON)=RIGHT2(LSON)=SIGN1(rt)*WIDTH(LSON);
        SUM1(LSON)=LEFT1(LSON)=RIGHT1(LSON)=(SIGN1(rt)^1)*WIDTH(LSON);
        SIGN1(RSON)=SIGN1(rt);
		SIGN2(RSON)=0;
        DATA(RSON)=SUM2(RSON)=LEFT2(RSON)=RIGHT2(RSON)=SIGN1(rt)*WIDTH(RSON);
        SUM1(RSON)=LEFT1(RSON)=RIGHT1(RSON)=(SIGN1(rt)^1)*WIDTH(RSON);
        SIGN1(rt)=-1;
    }
    if(SIGN2(rt)){
        SIGN2(LSON)^=1;
        DATA(LSON)=WIDTH(LSON)-DATA(LSON);
        swap(SUM1(LSON),SUM2(LSON));
        swap(LEFT1(LSON),LEFT2(LSON));swap(RIGHT1(LSON),RIGHT2(LSON));
        SIGN2(RSON)^=1;
        DATA(RSON)=WIDTH(RSON)-DATA(RSON);
        swap(SUM1(RSON),SUM2(RSON));
        swap(LEFT1(RSON),LEFT2(RSON));swap(RIGHT1(RSON),RIGHT2(RSON));
        SIGN2(rt)=0;
    }
}
void buildtree(int l,int r,int rt){
    int mid;
    LSIDE(rt)=l;RSIDE(rt)=r;
    SIGN1(rt)=-1;SIGN2(rt)=0;
    if(l==r){
    	int x=read();
        DATA(rt)=LEFT2(rt)=RIGHT2(rt)=SUM2(rt)=x;
        LEFT1(rt)=RIGHT1(rt)=SUM1(rt)=x^1;
        return;
    }
    mid=l+r>>1;
    buildtree(l,mid,LSON);
    buildtree(mid+1,r,RSON);
    pushup(rt);
}
void update_all(int l,int r,int c,int rt){
    int mid;
    if(l<=LSIDE(rt)&&RSIDE(rt)<=r){
        SIGN1(rt)=c;
        SIGN2(rt)=0;
        DATA(rt)=LEFT2(rt)=RIGHT2(rt)=SUM2(rt)=c*WIDTH(rt);
        LEFT1(rt)=RIGHT1(rt)=SUM1(rt)=(c^1)*WIDTH(rt);
        pushdown(rt);
        return;
    }
    pushdown(rt);
    mid=LSIDE(rt)+RSIDE(rt)>>1;
    if(l<=mid)update_all(l,r,c,LSON);
    if(mid<r)update_all(l,r,c,RSON);
    pushup(rt);
}
void update_false(int l,int r,int rt){
    int mid;
    if(l<=LSIDE(rt)&&RSIDE(rt)<=r){
        SIGN2(rt)^=1;
        DATA(rt)=WIDTH(rt)-DATA(rt);
        swap(SUM1(rt),SUM2(rt));
        swap(LEFT1(rt),LEFT2(rt));swap(RIGHT1(rt),RIGHT2(rt));
        pushdown(rt);
        return;
    }
    pushdown(rt);
    mid=LSIDE(rt)+RSIDE(rt)>>1;
    if(l<=mid)update_false(l,r,LSON);
    if(mid<r)update_false(l,r,RSON);
    pushup(rt);
}
int query_all(int l,int r,int rt){
    int mid,ans=0;
    if(l<=LSIDE(rt)&&RSIDE(rt)<=r)
    return DATA(rt);
    pushdown(rt);
    mid=LSIDE(rt)+RSIDE(rt)>>1;
    if(l<=mid)ans+=query_all(l,r,LSON);
    if(mid<r)ans+=query_all(l,r,RSON);
    return ans;
}
node query_length(int l,int r,int rt){
    int mid;
    if(l<=LSIDE(rt)&&RSIDE(rt)<=r)
    return a[rt];
    pushdown(rt);
    mid=LSIDE(rt)+RSIDE(rt)>>1;
    node ans,ls,rs;
    ans=ls=rs=(node){0,0,0,0,0,0,0,0,0,0,0};
    if(l<=mid)ls=query_length(l,r,LSON);
    if(mid<r)rs=query_length(l,r,RSON);
    ans.sum1=max(ls.right1+rs.left1,max(ls.sum1,rs.sum1));
	ans.sum2=max(ls.right2+rs.left2,max(ls.sum2,rs.sum2));
    ans.left1=ls.left1;ans.right1=rs.right1;
    ans.left2=ls.left2;ans.right2=rs.right2;
    if(ls.left1==WIDTH(LSON))ans.left1+=rs.left1;
    if(ls.left2==WIDTH(LSON))ans.left2+=rs.left2;
    if(rs.right1==WIDTH(RSON))ans.right1+=ls.right1;
    if(rs.right2==WIDTH(RSON))ans.right2+=ls.right2;
    return ans;
}
int main(){
    int f,x,y;
    n=read();m=read();
    buildtree(1,n,1);
    while(m--){
        f=read();x=read()+1;y=read()+1;
        switch(f){
            case 0:{
                update_all(x,y,0,1);
                break;
            }
            case 1:{
                update_all(x,y,1,1);
                break;
            }
            case 2:{
                update_false(x,y,1);
                break;
            }
            case 3:{
                printf("%d\n",query_all(x,y,1));
                break;
            }
            case 4:{
                node s=query_length(x,y,1);
                printf("%d\n",s.sum2);
                break;
            }
        }
    }
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值