SCOI 2010 序列操作

题目描述

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都需要给出回答,聪明的程序员们,你们能帮助他吗?

一道坑爹的线段树,我们维护7个信息,区间左右段点值,左右端点的连续长度,区间内的最长0串和1串。注意标记合并,翻转标记是xor更新的。覆盖标记遇上翻转标记是改覆盖标记类型。或者覆盖。

#include<bits/stdc++.h>
#define sight(x) ('0'<=x&&x<='9')
#define MID ((l+r)>>1)
#define max(x,y) (x)>(y)?(x):(y) 
#define node No
#define o(x) (x=(x&1)+1)
#define L(x) ((x)<<1)
#define R(x) ((x)<<1|1)
#define La lazy
#define N 400007
using namespace std;
inline void read(int &x) {
    static char c; static int b;
    for (b=1,c=getchar();!sight(c);c=getchar()) if (c=='-') b=-1;
    for (x=0;sight(c);c=getchar()) x=x*10+c-48;
    x*=b;
}
struct Node{
    int sum,l,r,llen,rlen,ma[2],siz;
    inline void add(Node x,Node y){
        sum=x.sum+y.sum; siz=x.siz+y.siz;
        l=x.l; r=y.r;
        ma[0]=max(x.ma[0],y.ma[0]); ma[1]=max(x.ma[1],y.ma[1]);
        if (x.r==y.l) ma[x.r]=max(ma[x.r],x.rlen+y.llen);
        llen=x.llen; rlen=y.rlen;
        if (x.llen==x.siz) llen=x.llen+((y.l==x.r)?y.llen:0);
        if (y.rlen==y.siz) rlen=y.rlen+((y.l==x.r)?x.rlen:0);
    }
    inline void G1() {
        sum=siz-sum;
        l^=1,r^=1; swap(ma[0],ma[1]);
    }
    inline void L1(int x) {
        sum=x?siz:0;
        l=r=x; ma[x]=siz; ma[x^1]=0; llen=rlen=siz;
    }
}T[N],RR;
int La[N],La1[N];
inline void updata(int node){
    if (La[No]) { La[L(No)]=La[R(No)]=La[No];
    T[L(No)].L1(La[No]&1); La1[L(No)]=0;
    T[R(No)].L1(La[No]&1); La1[R(No)]=0; La[No]=0; return;}
    if (La1[No]) { 
    if (La[L(No)]) o(La[L(No)]),La1[L(No)]=0; else La1[L(No)]^=1;
    if (La[R(No)]) o(La[R(No)]),La1[R(No)]=0; else La1[R(No)]^=1;
    La1[No]=0; T[L(No)].G1(); T[R(No)].G1(); return;}
}
void build(int node,int l,int r){
    if (l==r) {
        read(T[node].sum);
        T[node].l=T[node].r=T[node].sum;
        T[node].llen=T[node].rlen=T[node].siz=1;
        T[node].ma[T[node].sum]=1;
        return;
    }
    build(L(No),l,MID); build(R(No),MID+1,r);
    T[node].add(T[L(No)],T[R(No)]);
}
void change(int node,int l,int r,int L,int R,int col){
    if (L<=l&&r<=R) {   int    XX=col&3;
        if (XX) { La1[No]=0; La[No]=XX; T[No].L1(XX&1);}  
        else { if (La[No]) o(La[No]),La1[No]=0; else La1[No]^=1; T[No].G1();
        } return;
    }
    if (La[node]||La1[node]) updata(node);
    if (R<=MID) change(L(No),l,MID,L,R,col); else
    if (L> MID) change(R(No),MID+1,r,L,R,col); else
    change(L(No),l,MID,L,MID,col),change(R(No),MID+1,r,MID+1,R,col);
    T[No].add(T[L(No)],T[R(No)]);
}
Node query(int node,int l,int r,int L,int R){
    if (L<=l&&r<=R) return T[node];
    if (La[node]||La1[node]) updata(node);
    if (R<=MID) return query(L(No),l,MID,L,R); 
    if (L> MID) return query(R(No),MID+1,r,L,R); 
    Node XX;
    XX.add(query(L(No),l,MID,L,MID),query(R(No),MID+1,r,MID+1,R));
    return XX;
}
void write(int x){
    if (x<10) {putchar('0'+x);return;}write(x/10); putchar('0'+x%10);
}
int n,m,op,X,Y;
int main () {
    freopen("a.in","r",stdin);
    read(n); read(m);
    build(1,1,n);
    while(m--) {
        read(op); read(X); read(Y); X++; Y++;
        switch (op){
            case 0:change(1,1,n,X,Y,2); break;
            case 1:change(1,1,n,X,Y,1); break;
            case 2:change(1,1,n,X,Y,4); break;
            case 3:RR=query(1,1,n,X,Y);write(RR.sum);putchar('\n'); break;
            case 4:RR=query(1,1,n,X,Y);write(RR.ma[1]);putchar('\n'); break;
        }
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/rrsb/p/8006676.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值