HDU-3397:Sequence operation(区间更新之合集?)


题目链接:点击打开链接


题目大意:

题目给你一段随机的01串,有五种操作。

(1):将某段区间的数全部变为0

(2):将某段区间的数全部变为1

(3):将某段区间的0变为1,1变为0

(4):统计当前区间的1的个数

(5):统计当前区间的最长连续1的个数

解题思路:

看到这道题,仿佛看到了自己目前做的所有线段树区间更新的影子。首先先分析查询,查询1的个数,这个肯定就要统计当前区间内所有1的个数。

还要求区间内连续1的最长长度,那么就是左最长右最长区间最长进行区间更新就行。刚开始我还维护了0的情况,因为考虑到翻转,但是写完之后发现维护的关于0的这些值并没有什么用,因为更新有点特殊。

接下来就是更新,更新显而易见操作1和操作2是可以打延迟标记的,但是操作3呢?虽然听说取反直接更新到子节点貌似可以卡时间过,但是这里还是说下正确的方法,

其实思路和HDU4578很像,也是因为刚做那道题所以这道题很快想出了更新思路。那就是有前提条件的延迟更新(我自己瞎说的)

操作3如果在当前区间已经进行过操作1和2的情况下,就可以延迟更新,因为节点会有个值存当前应该将整个区间赋为哪个数。那么如果进行过操作1或2的话,就直接将值取反就可以,不影响延迟更新,否则就更新到子节点,一定要想通这一点,剩下的就是正常的线段树操作了,

这道题一定要思路清晰再写,写了以后想再练相似的推荐HDU4578,wa了心平气和仔细找bug,反正我是一遍AC的(逃,

具体的话可以看代码,


#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <queue>
#include <map>
#include <algorithm>
#include <set>
#include <functional>
#define rank ra
#define lson rt<<1
#define rson rt<<1|1
#define pb push_back
using namespace std;
typedef long long ll;
int n,m,ans;
int a[100010];
struct node
{
    int l,r,mid;
    int sum1;       //记录当前区间1的值
    int l1,r1,m1;   //记录左最长右最长区间最长
    int cnt;        //记录当前区间应该被赋为0还是1
    int lazy;       //延迟标记
}t[500000];
void pushdown(int rt)
{
    if(t[rt].lazy)
    {
        if(t[rt].cnt)       //如果为1更新一系列操作
        {
            t[lson].m1=t[lson].r-t[lson].l+1;
            t[lson].l1=t[lson].m1;t[lson].r1=t[lson].m1;
            t[lson].sum1=t[lson].m1;
            t[rson].m1=t[rson].r-t[rson].l+1;
            t[rson].l1=t[rson].m1;t[rson].r1=t[rson].m1;
            t[rson].sum1=t[rson].m1;
        }
        else            //为0同上
        {
            t[lson].m1=0;t[lson].l1=0;t[lson].r1=0;
            t[lson].sum1=0;
            t[rson].m1=0;t[rson].l1=0;t[rson].r1=0;
            t[rson].sum1=0;
        }
        t[lson].lazy=t[rson].lazy=1;
        t[lson].cnt=t[rson].cnt=t[rt].cnt;
        t[rt].lazy=0;
    }
}
void pushup(int rt)     //自下往上区间更新
{
    t[rt].sum1=t[lson].sum1+t[rson].sum1;
    if(t[lson].l1==t[lson].r-t[lson].l+1)
        t[rt].l1=t[lson].l1+t[rson].l1;
    else
        t[rt].l1=t[lson].l1;
    if(t[rson].r1==t[rson].r-t[rson].l+1)
        t[rt].r1=t[lson].r1+t[rson].r1;
    else
        t[rt].r1=t[rson].r1;
    t[rt].m1=max(max(t[lson].m1,t[rson].m1),t[lson].r1+t[rson].l1);
}
void build(int l,int r,int rt)
{
    int mid=(l+r)>>1;
    t[rt].l=l;t[rt].r=r;
    t[rt].mid=mid;
    t[rt].lazy=0;
    t[rt].cnt=0;
    if(l==r)
    {
        if(a[t[rt].l])      //根据1,0更新情况
        {
            t[rt].sum1=1;
            t[rt].l1=1;t[rt].r1=1;t[rt].m1=1;
        }
        else
        {
            t[rt].sum1=0;
            t[rt].l1=0;t[rt].r1=0;t[rt].m1=0;
        }
        return ;
    }
    build(l,mid,lson);
    build(mid+1,r,rson);
    pushup(rt);
}
void update(int l,int r,int flag,int rt)//如果是操作1 2或者是操作3
{                                       //但是当前进行过操作1 2被打了延迟标记
    if(l<=t[rt].l&&t[rt].r<=r&&((flag==0||flag==1)||(t[rt].lazy==1&&flag==2)))  
    {
        if(flag==0)     //正常延迟更新
        {
            t[rt].lazy=1;
            t[rt].cnt=0;
        }
        if(flag==1)
        {
            t[rt].lazy=1;
            t[rt].cnt=1;
        }
        if(flag==2)         //取反
            t[rt].cnt^=1;
        if(t[rt].cnt)       //根据cnt值进行更新操作
        {
            t[rt].m1=t[rt].r-t[rt].l+1;
            t[rt].l1=t[rt].m1;t[rt].r1=t[rt].m1;
            t[rt].sum1=t[rt].m1;
        }
        else
        {
            t[rt].m1=0;t[rt].l1=0;t[rt].r1=0;
            t[rt].sum1=0;
        }
        return ;
    }
    if(l<=t[rt].l&&t[rt].r<=r&&t[rt].l==t[rt].r&&flag==2)
    {
        t[rt].sum1^=1;          //操作3更新到子节点取反即可
        t[rt].l1^=1;t[rt].r1^=1;t[rt].m1^=1;
        return ;
    }
    pushdown(rt);
    if(l<=t[rt].mid)    
        update(l,r,flag,lson);
    if(r>t[rt].mid)
        update(l,r,flag,rson);
    pushup(rt);
}
void query1(int l,int r,int rt)     //查询1的个数
{
    if(l<=t[rt].l&&t[rt].r<=r)
    {
        ans += t[rt].sum1;
        return ;
    }
    pushdown(rt);
    if(l<=t[rt].mid)
        query1(l,r,lson);
    if(r>t[rt].mid)
        query1(l,r,rson);
    pushup(rt);
}
int query2(int l,int r,int rt)      //查询最长连续1的长度
{
    if(l==t[rt].l&&r==t[rt].r)
        return t[rt].m1;
    pushdown(rt);
    if(r<=t[rt].mid)
        return query2(l,r,lson);
    else if(l>t[rt].mid)
        return query2(l,r,rson);
    else
    {
        int aa=query2(l,t[rt].mid,lson);
        int bb=query2(t[rt].mid+1,r,rson);
        int cc=0;
        cc=min(t[lson].r1,t[rt].mid-l+1)+min(t[rson].l1,r-t[rt].mid);
        return max(max(aa,bb),cc);
    }
    pushup(rt);
}
int main()
{
    int QAQ;
    scanf("%d",&QAQ);
    while(QAQ--)
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        build(1,n,1);
        int q,l,r;
        while(m--)
        {
            scanf("%d%d%d",&q,&l,&r);
            if(q>=0&&q<=2)
                update(l+1,r+1,q,1);    //注意加1 刚上来还纳闷为啥样例没过
            if(q==3)
            {
                ans=0;
                query1(l+1,r+1,1);
                printf("%d\n",ans);
            }
            if(q==4)
            {
                ans=query2(l+1,r+1,1);
                printf("%d\n",ans);
            }
        }
    }
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值