UESTC 1592 An easy problem B 线段树区间合并

An easy problem B

Time Limit: 2000/1000MS (Java/Others)     Memory Limit: 65535/65535KB (Java/Others)

Submit  Status

N个数排成一列,每个数的大小为1或者0。有两种操作,第一种操作是把一段区间内的每个数异或1,第二种操作是询问区间内最长连续1的长度。

Input

第一行一个整数N(1≤N≤100000),表示N个数。第二行N个数。接下来一行一个整数M(1≤M≤100000),表示M个操作,接下来M行每行三个整数K,L,R。K=1表示把L到R这段区间的数全部异或上1,K=0表示询问L到R这段区间内最长连续1的长度。

Output

对于每个询问,输出对应的答案,每个询问占一行。

Sample input and output

Sample Input
Sample Output

5

0 1 0 0 1

5

0 1 4

1 1 1

0 1 4

1 3 4

0 1 4

1

2

4

Source

2017 UESTC Training for Data Structures 

UESTC 1592 An easy problem B

My Solution

题意:区间更新把该区间内所有的数异或1,区间查询该区间内最长连续1的长度。

线段树区间合并
每个节点维护十元组
int summid[4*MAXN][2], suml[4*MAXN][2], sumr[4*MAXN][2], ans[4*MAXN][2], lazy[4*MAXN], rev[4*MAXN];
summid[Ind][k]表示该区间的中间的最长连续k(0|1)的长度,
suml[Ind][k]描述该区间从左端点开始的最长连续k(0|1)的长度,
sumr[Ind][k]表示从该区间右端点结束的最长连续k(0|1)的长度,
ans[Ind][k]表示该区间的最长连续k(0|1)的长度,
lazy[Ind]为延迟操作的标记,
rev[Ind]为旋转(异或)操作的标记。

每次pushup的时候,刷新这十元组,
inline void pushupk(int l, int r, int Ind, int k)
{
    int mid = (l + r) >> 1;
    if(mid – l + 1 == summid[Ind<<1][k]) suml[Ind][k] = summid[Ind<<1][k] + suml[Ind<<1|1][k];
    else suml[Ind][k] = suml[Ind<<1][k];
    if(r – (mid+1) + 1 == summid[Ind<<1|1][k]) sumr[Ind][k] = sumr[Ind<<1][k] + summid[Ind<<1|1][k];
    else sumr[Ind][k] = sumr[Ind<<1|1][k];
    summid[Ind][k] = max(max(summid[Ind<<1][k], summid[Ind<<1|1][k]), sumr[Ind<<1][k] + suml[Ind<<1|1][k]);
    ans[Ind][k] = max(max(ans[Ind<<1][k], ans[Ind<<1|1][k]), max(suml[Ind][k], sumr[Ind][k]));
    ans[Ind][k] = max(ans[Ind][k], summid[Ind][k]);
}
inline void pushup(int l, int r, int Ind)
{
    pushupk(l, r, Ind, 0);
    pushupk(l, r, Ind, 1);
}

每次如果有被标记过的延迟标记这pushdown
inline void pushdownk(int Ind)
{
    swap(suml[Ind][0], suml[Ind][1]);
    swap(sumr[Ind][0], sumr[Ind][1]);
    swap(summid[Ind][0], summid[Ind][1]);
    swap(ans[Ind][0], ans[Ind][1]);
}
inline void pushdown(int Ind)
{
    lazy[Ind<<1] ^= 1;
    lazy[Ind<<1|1] ^= 1;
    rev[Ind<<1] ^= 1;
    rev[Ind<<1|1] ^= 1;
    if(rev[Ind<<1]){
        pushdownk(Ind<<1);
        rev[Ind<<1] ^= 1;
    }
    if(rev[Ind<<1|1]){
        pushdownk(Ind<<1|1);
        rev[Ind<<1|1] ^= 1;
    }
    lazy[Ind] = 0;
}

查询的时候,可以建立5个全局int findans, lans, rans, midans, rl;
每次查询到该最小区间即if(a <= l && r <= b)的时候刷新这个全局的四元组,
这样就不需要给查询函数设定返回值了,写起来比较方便,
即直接对该查询区间分成的子区间进行合并,具体见代码。
复杂度 O(nlogn)

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long LL;
const int MAXN = 1e5 + 8;
const int INF = -2e9+8;

int summid[4*MAXN][2], suml[4*MAXN][2], sumr[4*MAXN][2], ans[4*MAXN][2], lazy[4*MAXN], rev[4*MAXN];
int findans, lans, rans, midans, rl;
int sz;
inline void pushdownk(int Ind)
{
    swap(suml[Ind][0], suml[Ind][1]);
    swap(sumr[Ind][0], sumr[Ind][1]);
    swap(summid[Ind][0], summid[Ind][1]);
    swap(ans[Ind][0], ans[Ind][1]);
}
inline void pushdown(int Ind)
{
    lazy[Ind<<1] ^= 1;
    lazy[Ind<<1|1] ^= 1;
    rev[Ind<<1] ^= 1;
    rev[Ind<<1|1] ^= 1;
    if(rev[Ind<<1]){
        pushdownk(Ind<<1);
        rev[Ind<<1] ^= 1;
    }
    if(rev[Ind<<1|1]){
        pushdownk(Ind<<1|1);
        rev[Ind<<1|1] ^= 1;
    }
    lazy[Ind] = 0;
}
inline void pushupk(int l, int r, int Ind, int k)
{
    int mid = (l + r) >> 1;
    if(mid - l + 1 == summid[Ind<<1][k]) suml[Ind][k] = summid[Ind<<1][k] + suml[Ind<<1|1][k];
    else suml[Ind][k] = suml[Ind<<1][k];
    if(r - (mid+1) + 1 == summid[Ind<<1|1][k]) sumr[Ind][k] = sumr[Ind<<1][k] + summid[Ind<<1|1][k];
    else sumr[Ind][k] = sumr[Ind<<1|1][k];
    summid[Ind][k] = max(max(summid[Ind<<1][k], summid[Ind<<1|1][k]), sumr[Ind<<1][k] + suml[Ind<<1|1][k]);
    ans[Ind][k] = max(max(ans[Ind<<1][k], ans[Ind<<1|1][k]), max(suml[Ind][k], sumr[Ind][k]));
    ans[Ind][k] = max(ans[Ind][k], summid[Ind][k]);
}
inline void pushup(int l, int r, int Ind)
{
    pushupk(l, r, Ind, 0);
    pushupk(l, r, Ind, 1);
}
inline void _Modify(int a, int b, int l, int r, int Ind, int d){
    if(a <= l && r <= b){
        lazy[Ind] ^= d;
        rev[Ind] ^= d;
        if(rev[Ind]){
            pushdownk(Ind);
            rev[Ind] ^= 1;
        }
        return;
    }
    int mid = (l + r) >> 1;
    if(lazy[Ind]) pushdown(Ind);
    if(a <= mid){ _Modify(a, b, l, mid, Ind<<1, d); }
    if(b > mid){ _Modify(a, b, mid + 1, r,Ind<<1|1, d); }
    pushup(l, r, Ind);
}
inline void _Query(int a, int b, int l, int r, int Ind){
    if(a <= l && r <= b){
        if(findans == INF){
            findans = ans[Ind][1];
            lans = suml[Ind][1];
            rans = sumr[Ind][1];
            midans = summid[Ind][1];
            rl = r - l + 1;
            return;
        }
        if(rl == midans) lans = midans + suml[Ind][1];
        midans = max(max(midans, summid[Ind][1]), rans + suml[Ind][1]);
        if(r - l + 1 == summid[Ind][1]) rans = rans + summid[Ind][1];
        else rans = sumr[Ind][1];
        findans = max(max(findans, ans[Ind][1]), max(rans, rans));
        findans = max(findans, midans);
        rl += r - l + 1;
        return;
    }
    int mid = (l + r) >> 1;
    if(lazy[Ind]) pushdown(Ind);
    if(a <= mid) { _Query(a, b, l, mid, Ind<<1); }
    if(b > mid) { _Query(a, b, mid + 1, r, Ind<<1|1);}
    pushup(l, r, Ind);
}
inline void _Build(int l, int r, int Ind){
    if(l == r){
        lazy[Ind] = 0;
        rev[Ind] = 0;
        suml[Ind][0] = sumr[Ind][0] = summid[Ind][0] = ans[Ind][0] = 1;
        return;
    }
    int mid = (l + r) >> 1;
    _Build(l, mid, Ind<<1);
    _Build(mid + 1, r,Ind<<1|1);
    pushup(l, r, Ind);
}
inline void Modify(int a, int b, int d){return _Modify(a, b, 1, sz, 1, d);}
inline void Query(int a, int b) {return _Query(a, b, 1, sz, 1);}
inline void Build(){return _Build(1, sz, 1);}

int main()
{
    #ifdef LOCAL
    freopen("b.txt", "r", stdin);
    //freopen("b.out", "w", stdout);
    int T = 1;
    while(T--){
    #endif // LOCAL
    //ios::sync_with_stdio(false); cin.tie(0);

    int n, m, i, x, t, l, r;
    scanf("%d", &n);
    sz = n;
    Build();
    for(i = 1; i <= n; i++){
        scanf("%d", &x);
        Modify(i, i, x);
    }
    scanf("%d", &m);
    while(m--){
        scanf("%d%d%d", &t, &l, &r);
        if(t == 0){
            findans = lans = rans = midans = INF;
            Query(l, r);
            printf("%d\n", findans);
        }
        else{
            Modify(l, r, 1);
        }
    }

    #ifdef LOCAL
    cout << endl;
    }
    #endif // LOCAL
    return 0;
}

  Thank you!

                                                                                                                                             ——from ProLights

    原文作者:B树
    原文地址: https://blog.csdn.net/ProLightsfxjh/article/details/72320747
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞