【线段树】 HDOJ 3397 Sequence operation

五种操作,三种更新,两种查询,合并区间。。。算是比较经典的题目了,操作和查询都比较常规,合并的题目之前也写过几道。。。不过这道题目要用到两种lazy标记,因为异或和全为1,全为0不能合并成一种。。所以写pushdown和写updata的时候要小心,先全改,再异或,先异或,再全改,先异或再异或。。。几种情况都要考虑清楚,不然容易错。。。总的来说这道题目还是比较经典的。。。


#include <iostream>
#include <sstream>
#include <algorithm>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <bitset>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <climits>
#define maxn 400005
#define eps 1e-6
#define mod 1000000007
#define INF 99999999
#define lowbit(x) (x&(-x))
#define lson o<<1, L, mid
#define rson o<<1 | 1, mid+1, R
typedef long long LL;
using namespace std;

int mark1[maxn], mark2[maxn];
int sum[maxn], init[maxn];
int lmax[2][maxn], rmax[2][maxn];
int segmax[2][maxn], segnum[2][maxn];
int ansl[maxn], ansv[maxn];
int n, m, k;
int ql, qr, ans;

void pushup(int o, int L, int R, int c)
{
    int tmp=0, mid=(L+R)>>1;
    if(rmax[c][o<<1] && lmax[c][o<<1 | 1]) tmp=rmax[c][o<<1]+lmax[c][o<<1 | 1];
    if(tmp>=segmax[c][o<<1] && tmp>=segmax[c][o<<1 | 1])
        segmax[c][o]=tmp, segnum[c][o]=mid-rmax[c][o<<1]+1;
    else if(segmax[c][o<<1]>segmax[c][o<<1 | 1])
        segmax[c][o]=segmax[c][o<<1], segnum[c][o]=segnum[c][o<<1];
    else segmax[c][o]=segmax[c][o<<1 | 1], segnum[c][o]=segnum[c][o<<1 | 1];
    if(segnum[c][o]==L) lmax[c][o]=segmax[c][o];
    else lmax[c][o]=lmax[c][o<<1];
    if(segnum[c][o]+segmax[c][o]-1==R) rmax[c][o]=segmax[c][o];
    else rmax[c][o]=rmax[c][o<<1 | 1];
    sum[o]=sum[o<<1]+sum[o<<1 | 1];
}
void build(int o, int L, int R)
{
    if(L==R){
        sum[o]=init[L];
        if(init[L]){
            segmax[0][o]=0, segmax[1][o]=1, segnum[0][o]=L, segnum[1][o]=L;
            lmax[0][o]=0, rmax[0][o]=0, lmax[1][o]=1, rmax[1][o]=1;
        }
        else{
            segmax[0][o]=1, segmax[1][o]=0, segnum[0][o]=L, segnum[1][o]=L;
            lmax[0][o]=1, rmax[0][o]=1, lmax[1][o]=0, rmax[1][o]=0;
        }
        return;
    }
    int mid=(R+L)>>1;
    build(lson);
    build(rson);
    pushup(o, L, R, 0);
    pushup(o, L, R, 1);
}
void pushdown1(int o, int L, int R)
{
    if(mark1[o]==-1) return;
    int mid=(R+L)>>1;
    if(mark1[o]==0){
        segnum[0][o<<1]=L, segnum[0][o<<1 | 1]=mid+1;
        lmax[0][o<<1]=rmax[0][o<<1]=segmax[0][o<<1]=mid-L+1;
        lmax[0][o<<1 | 1]=rmax[0][o<<1 | 1]=segmax[0][o<<1 | 1]=R-mid;
        segnum[1][o<<1]=L, segnum[1][o<<1 | 1]=mid+1;
        lmax[1][o<<1]=rmax[1][o<<1]=segmax[1][o<<1]=0;
        lmax[1][o<<1 | 1]=rmax[1][o<<1 | 1]=segmax[1][o<<1 | 1]=0;
        sum[o<<1]=sum[o<<1 | 1]=0;
    }
    else{
        segnum[1][o<<1]=L, segnum[1][o<<1 | 1]=mid+1;
        lmax[1][o<<1]=rmax[1][o<<1]=segmax[1][o<<1]=mid-L+1;
        lmax[1][o<<1 | 1]=rmax[1][o<<1 | 1]=segmax[1][o<<1 | 1]=R-mid;
        segnum[0][o<<1]=L, segnum[0][o<<1 | 1]=mid+1;
        lmax[0][o<<1]=rmax[0][o<<1]=segmax[0][o<<1]=0;
        lmax[0][o<<1 | 1]=rmax[0][o<<1 | 1]=segmax[0][o<<1 | 1]=0;
        sum[o<<1]=mid-L+1, sum[o<<1 | 1]=R-mid;
    }
    mark1[o<<1]=mark1[o<<1 | 1]=mark1[o];
    mark1[o]=-1, mark2[o]=0;
}
void pushdown2(int o, int L, int R)
{
    if(!mark2[o]) return;
    int mid=(R+L)>>1;
    swap(lmax[0][o<<1], lmax[1][o<<1]), swap(lmax[0][o<<1 | 1], lmax[1][o<<1 | 1]);
    swap(rmax[0][o<<1], rmax[1][o<<1]), swap(rmax[0][o<<1 | 1], rmax[1][o<<1 | 1]);
    swap(segmax[0][o<<1], segmax[1][o<<1]), swap(segmax[0][o<<1 | 1], segmax[1][o<<1 | 1]);
    swap(segnum[0][o<<1], segnum[1][o<<1]), swap(segnum[0][o<<1 | 1], segnum[1][o<<1 | 1]);
    sum[o<<1]=mid-L+1-sum[o<<1], sum[o<<1 | 1]=R-mid-sum[o<<1 | 1];
    if(mark1[o<<1]!=-1) mark1[o<<1]^=1, mark2[o<<1]=0;
    else mark2[o<<1]^=1;
    if(mark1[o<<1 | 1]!=-1) mark1[o<<1 | 1]^=1, mark2[o<<1 | 1]=0;
    else mark2[o<<1 | 1]^=1;
    mark2[o]=0;
}
void updata(int o, int L, int R)
{
    if(ql<=L && qr>=R){
        if(k==1){
            mark1[o]=0, mark2[o]=0;
            segnum[0][o]=segnum[1][o]=L, sum[o]=0;
            lmax[0][o]=rmax[0][o]=segmax[0][o]=R-L+1;
            lmax[1][o]=rmax[1][o]=segmax[1][o]=0;
        }
        if(k==2){
            mark1[o]=1, mark2[o]=0;
            segnum[0][o]=segnum[1][o]=L, sum[o]=R-L+1;
            lmax[0][o]=rmax[0][o]=segmax[0][o]=0;
            lmax[1][o]=rmax[1][o]=segmax[1][o]=R-L+1;
        }
        if(k==3){
            if(mark1[o]!=-1) mark1[o]^=1;
            else mark2[o]^=1;
            sum[o]=R-L+1-sum[o];
            swap(segmax[0][o], segmax[1][o]);
            swap(segnum[0][o], segnum[1][o]);
            swap(lmax[0][o], lmax[1][o]);
            swap(rmax[0][o], rmax[1][o]);
        }
        return;
    }
    pushdown2(o, L, R);
    pushdown1(o, L, R);
    int mid=(R+L)>>1;
    if(ql<=mid) updata(lson);
    if(qr>mid) updata(rson);
    pushup(o, L, R, 0);
    pushup(o, L, R, 1);
}
void _query(int o, int L, int R)
{
    if(ql<=L && qr>=R){
        ans+=sum[o];
        return;
    }
    pushdown2(o, L, R);
    pushdown1(o, L, R);
    int mid=(R+L)>>1;
    if(ql<=mid) _query(lson);
    if(qr>mid) _query(rson);
    pushup(o, L, R, 0);
    pushup(o, L, R, 1);
}
void _pushup(int o, int L, int R)
{
    int mid=(R+L)>>1, tmp=0;
    if(ql>mid || qr<=mid || !lmax[1][o<<1 | 1] || !rmax[1][o<<1]) tmp=0;
    else tmp=min(mid+lmax[1][o<<1 | 1], qr)-max(mid-rmax[1][o<<1]+1, ql)+1;
    if(tmp>=ansv[o<<1] && tmp>=ansv[o<<1 | 1]) ansv[o]=tmp, ansl[o]=max(mid-rmax[1][o<<1]+1, ql);
    else if(ansv[o<<1]>ansv[o<<1 | 1]) ansv[o]=ansv[o<<1], ansl[o]=ansl[o<<1];
    else ansv[o]=ansv[o<<1 | 1], ansl[o]=ansl[o<<1 | 1];
    ansl[o<<1]=ansl[o<<1 | 1]=ansv[o<<1]=ansv[o<<1 | 1]=0;
}
void query(int o, int L, int R)
{
    if(ql<=L && qr>=R){
        ansl[o]=segnum[1][o], ansv[o]=segmax[1][o];
        return;
    }
    pushdown2(o, L, R);
    pushdown1(o, L, R);
    int mid=(R+L)>>1;
    if(ql<=mid) query(lson);
    if(qr>mid) query(rson);
    pushup(o, L, R, 0);
    pushup(o, L, R, 1);
    _pushup(o, L, R);
}
void solve(void)
{
    while(m--){
        scanf("%d%d%d",&k,&ql,&qr);
        k++, ql++, qr++;
        if(k>=4){
            ans=0;
            if(k==4){
                _query(1, 1, n);
                printf("%d\n", ans);
            }
            else{
                query(1, 1, n);
                printf("%d\n", ansv[1]);
            }
        }
        else updata(1, 1, n);
    }
}
int main(void)
{
    int _;
    while(scanf("%d",&_)!=EOF){
        while(_--){
            scanf("%d%d",&n,&m);
            for(int i=1;i<=n;i++) scanf("%d",&init[i]);
            memset(mark1, -1, sizeof mark1);
            memset(mark2, 0, sizeof mark2);
            memset(ansl, 0, sizeof ansl);
            memset(ansv, 0, sizeof ansv);
            build(1, 1, n);
            solve();
        }
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值