现在的位置: 首页 > 综合 > 正文

HDU 3397 Sequence operation(线段树好题)

2017年12月17日 ⁄ 综合 ⁄ 共 3263字 ⁄ 字号 评论关闭

题目链接:Click here~~

题意:

很给力的线段树题,感觉对帮助理解线段树十分有帮助。写了 200 行,debug了 2 小时。好爽。

有一个数列,然后5种操作:

1、将 [a,b] 中所有数变成0。

2、将 [a,b] 中所有数变成1。

3、将 [a,b] 中所有数取反。

4、询问 [a,b] 中 1 的个数。

5、询问 [a,b] 中最长连续 1 的长度。

解题思路:

一眼过去肯定是线段树啊。考虑存些什么值才可以使问题能解。

首先,sum of 1 是肯定要存的。而且,它可以不依赖其他信息就在 O(1) 使区间的 sum 得到更新。

然后,最长连续 1 长度也是要存的。但是,考虑区间合并的时候,子区间的值并不能直接合并到父区间。( max{ 子区间 } ≠ 父区间 )

所以,我们还要记录每个区间从 左/右 开始的最长连续 1 的长度,那样,就可以解决区间合并的问题了。

等下,更新怎么办?操作 1、2 都好说,但是 3 怎么办?

没错,再相似的记录下最长连续 0。对于操作3,等价于于 1 和 0 的属性互换。

再给前三个操作分别弄个懒惰标记就行了,哈哈。

细节:

由于有两个标记,考虑标记的先后顺序会对结果产生影响。

怎么处理这个问题呢?

当执行操作 1、2 的时候,把操作 3 的标记擦除。

然后如果某个节点同时有 2 个标记,说明是先进行的操作 1、2 ,然后进行的操作 3 。

附代码。

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;

#define lson u<<1
#define rson u<<1|1

const int N = 1e5+5;

int cmd;

struct SegTree
{
    int l,r;
    int sum,lmax[2],rmax[2],max[2],to;
    bool xxor;
    inline int len(){
        return r-l;
    }
    inline int mid(){
        return l+r >> 1;
    }
}T[N<<2];

void push_up(int u)
{
    T[u].sum = T[lson].sum + T[rson].sum;

    for(int i=0;i<=1;i++)
    {
        T[u].max[i] = max(T[lson].rmax[i]+T[rson].lmax[i] , max(T[lson].max[i],T[rson].max[i]));

        if(T[lson].lmax[i] == T[lson].len())
            T[u].lmax[i] = T[lson].lmax[i] + T[rson].lmax[i];
        else
            T[u].lmax[i] = T[lson].lmax[i];

        if(T[rson].rmax[i] == T[rson].len())
            T[u].rmax[i] = T[lson].rmax[i] + T[rson].rmax[i];
        else
            T[u].rmax[i] = T[rson].rmax[i];
    }
}

void changeX(int u)
{
    T[u].sum = T[u].len() - T[u].sum;
    swap(T[u].max[0],T[u].max[1]);
    swap(T[u].lmax[0],T[u].lmax[1]);
    swap(T[u].rmax[0],T[u].rmax[1]);
}

void changeT(int u)
{
    int to = T[u].to;
    T[u].sum = to ? T[u].len() : 0;
    T[u].max[to] = T[u].lmax[to] = T[u].rmax[to] = T[u].len();
    T[u].max[to^1] = T[u].lmax[to^1] = T[u].rmax[to^1] = 0;
}

void push_down(int u)
{
    if(T[u].to != -1)
    {
        T[lson].to = T[rson].to = T[u].to;
        T[lson].xxor = T[rson].xxor = false;
        changeT(lson);
        changeT(rson);
        T[u].to = -1;
    }
    if(T[u].xxor)
    {
        T[lson].xxor ^= 1;
        T[rson].xxor ^= 1;
        changeX(lson);
        changeX(rson);
        T[u].xxor = false;
    }
}

void debug(int u)
{
    printf("***[%d,%d)***\n",T[u].l,T[u].r);
    printf("    sum=> %d\n",T[u].sum);
    for(int i=0;i<=1;i++)
    {
        printf("\t lmax[%d]:%d\n",i,T[u].lmax[i]);
        printf("\t rmax[%d]:%d\n",i,T[u].rmax[i]);
        printf("\t max[%d]:%d\n",i,T[u].max[i]);
    }
    puts("\n");
}

void build(int u,int l,int r)
{
    T[u].l = l , T[u].r = r;
    T[u].to = -1;
    T[u].xxor = false;
    if(l == r-1)
    {
        int num;
        scanf("%d",&num);
        T[u].sum = num;
        T[u].max[0] = T[u].lmax[0] = T[u].rmax[0] = num ^ 1;
        T[u].max[1] = T[u].lmax[1] = T[u].rmax[1] = num & 1;
        return ;
    }
    int m = T[u].mid();
    build(lson,l,m);
    build(rson,m,r);
    push_up(u);
}

void updata(int u,int l,int r)
{
    if(l == T[u].l && r == T[u].r)
    {
        if(cmd == 2)
        {
            T[u].xxor ^= 1;
            changeX(u);
        }
        else
        {
            T[u].to = cmd;
            T[u].xxor = false;
            changeT(u);
        }
        return ;
    }
    int m = T[u].mid();
    push_down(u);
    if(r <= m)
        updata(lson,l,r);
    else if(l >= m)
        updata(rson,l,r);
    else
        updata(lson,l,m) , updata(rson,m,r);
    push_up(u);
}

int queryS(int u,int l,int r)
{
    if(l == T[u].l && r == T[u].r)
    {
        return T[u].sum;
    }
    int m = T[u].mid();
    push_down(u);
    if(r <= m)
        return queryS(lson,l,r);
    else if(l >= m)
        return queryS(rson,l,r);
    else
        return queryS(lson,l,m) + queryS(rson,m,r);
}

int queryM(int u,int l,int r)
{
    if(l == T[u].l && r == T[u].r)
    {
        return T[u].max[1];
    }
    int m = T[u].mid();
    push_down(u);
    if(r <= m)
        return queryM(lson,l,r);
    else if(l >= m)
        return queryM(rson,l,r);
    else
    {
        int ans = max(queryM(lson,l,m),queryM(rson,m,r));

        ans = max(ans,min(m-l,T[lson].rmax[1])+min(r-m,T[rson].lmax[1]));

        return ans;
    }
}

int main()
{
    //freopen("in.ads","r",stdin);
    int z,n,Q;
    scanf("%d",&z);
    while(z--)
    {
        scanf("%d%d",&n,&Q);
        build(1,1,n+1);
        while(Q--)
        {
            int a,b;
            scanf("%d%d%d",&cmd,&a,&b);
            ++a , ++b;
            if(cmd <= 2)
                updata(1,a,b+1);
            else if(cmd == 3)
                printf("%d\n",queryS(1,a,b+1));
            else
                printf("%d\n",queryM(1,a,b+1));
        }
    }
	return 0;
}

抱歉!评论已关闭.