HDU 3397 线段树 双懒惰标记

这个是去年遗留历史问题,之前思路混乱,搞了好多发都是WA,就没做了

自从上次做了大白书上那个双重懒惰标记的题目,做这个就思路很清晰了

跟上次大白上那个差不多,这个也是有一个sets标记,代表这个区间全部置为0或者1,没有置位的时候为-1

还有个rev标记,代表翻转操作,0代表当前不翻,1代表当前翻

要注意一下优先级,发现有不同的弄法,我是这个弄得,有set操作的时候,set标记设值,并把当前节点的rev标记设为0,因为不管要不要rev,当前set操作肯定直接覆盖了

rev操作不改变set操作,在pushdown的时候,先考虑set标记再弄rev标记,这也是很好理解的,因为一旦rev和set共存,肯定是rev在set后面。

有几个细节要注意一下,一开始行云流水一气呵成,发现还是WA了,就是这几个地方,

1.除了set的时候强制给rev弄成0,其他任何时候对rev标记操作都是^1,取反,这个也很好理解,之前在pushdown里面我就是直接传值,肯定不对嘛

2.在pushdown里面的set下传操作也要记得把子树的rev标记抹除,一开始只在主修改函数里写了,这里没写,WA的不明不白,理由跟上面的一样

然后就基本上没问题了

#include <iostream>
#include <cstdio>
#include <cstring>
#define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r
using namespace std;
const int N=100000+10;
int d[N*3],maxc[N*3],lc[N*3],rc[N*3],maxc0[N*3],lc0[N*3],rc0[N*3];
int sets[N*3],rev[N*3];
int n,Q;
int A[N];
void up(int rt,int l,int r)
{
    int mid=(l+r)>>1;
    d[rt]=d[rt<<1]+d[rt<<1|1];
    maxc[rt]=max(maxc[rt<<1],maxc[rt<<1|1]);
    maxc[rt]=max(maxc[rt],lc[rt<<1|1]+rc[rt<<1]);
    lc[rt]=lc[rt<<1];
    rc[rt]=rc[rt<<1|1];
    if (lc[rt<<1]==mid-l+1) lc[rt]+=lc[rt<<1|1];
    if (rc[rt<<1|1]==r-mid) rc[rt]+=rc[rt<<1];

    maxc0[rt]=max(maxc0[rt<<1],maxc0[rt<<1|1]);
    maxc0[rt]=max(maxc0[rt],lc0[rt<<1|1]+rc0[rt<<1]);
    lc0[rt]=lc0[rt<<1];
    rc0[rt]=rc0[rt<<1|1];
    if (lc0[rt<<1]==mid-l+1) lc0[rt]+=lc0[rt<<1|1];
    if (rc0[rt<<1|1]==r-mid) rc0[rt]+=rc0[rt<<1];
}
void build(int rt,int l,int r)
{
    sets[rt]=-1;
    rev[rt]=0;
    if (l>=r){
        d[rt]=maxc[rt]=A[l];
        lc[rt]=rc[rt]=A[l];
        lc0[rt]=rc0[rt]=maxc0[rt]=1-A[l];
        return;
    }
    int mid=(l+r)>>1;
    build(lson);
    build(rson);
    up(rt,l,r);
}
void pushdown(int rt,int l,int r)
{
    if (l>=r) return;
    int mid=(l+r)>>1;
    if (sets[rt]>=0){
        maxc[rt<<1]=lc[rt<<1]=rc[rt<<1]=d[rt<<1]=(mid-l+1)*sets[rt];
        maxc[rt<<1|1]=lc[rt<<1|1]=rc[rt<<1|1]=d[rt<<1|1]=(r-mid)*sets[rt];

        maxc0[rt<<1]=lc0[rt<<1]=rc0[rt<<1]=(mid-l+1)*(1-sets[rt]);
        maxc0[rt<<1|1]=lc0[rt<<1|1]=rc0[rt<<1|1]=(r-mid)*(1-sets[rt]);

        sets[rt<<1]=sets[rt<<1|1]=sets[rt];
        rev[rt<<1]=rev[rt<<1|1]=0;
        sets[rt]=-1;

    }
    if (rev[rt]>0){
        d[rt<<1]=(mid-l+1)-d[rt<<1];
        d[rt<<1|1]=(r-mid)-d[rt<<1|1];

        int t1,t2,t3;
        t1=maxc[rt<<1];t2=lc[rt<<1];t3=rc[rt<<1];
        maxc[rt<<1]=maxc0[rt<<1];
        lc[rt<<1]=lc0[rt<<1];
        rc[rt<<1]=rc0[rt<<1];
        maxc0[rt<<1]=t1;
        lc0[rt<<1]=t2;
        rc0[rt<<1]=t3;
        t1=maxc[rt<<1|1];t2=lc[rt<<1|1];t3=rc[rt<<1|1];
        maxc[rt<<1|1]=maxc0[rt<<1|1];
        lc[rt<<1|1]=lc0[rt<<1|1];
        rc[rt<<1|1]=rc0[rt<<1|1];
        maxc0[rt<<1|1]=t1;
        lc0[rt<<1|1]=t2;
        rc0[rt<<1|1]=t3;
        rev[rt<<1]^=1;
        rev[rt<<1|1]^=1;
        rev[rt]=0;
    }
}
void change(int val,int L,int R,int rt,int l,int r)
{
    if (L<=l && r<=R){
        d[rt]=(r-l+1)*val;
        lc[rt]=rc[rt]=(r-l+1)*val;
        maxc[rt]=(r-l+1)*val;
        lc0[rt]=rc0[rt]=maxc0[rt]=(r-l+1)*(1-val);
        sets[rt]=val;
        rev[rt]=0;
        return;
    }
    pushdown(rt,l,r);
    int mid=(l+r)>>1;
    if (L>mid) change(val,L,R,rson);
    else
    if (R<=mid) change(val,L,R,lson);
    else{
        change(val,L,R,rson);
        change(val,L,R,lson);
    }
    up(rt,l,r);
}
void revers(int L,int R,int rt,int l,int r)
{

    if (L<=l && r<=R)
    {

        d[rt]=(r-l+1)-d[rt];
        int t1,t2,t3;
        t1=maxc[rt];t2=lc[rt];t3=rc[rt];
        maxc[rt]=maxc0[rt];lc[rt]=lc0[rt];rc[rt]=rc0[rt];
        maxc0[rt]=t1;lc0[rt]=t2;rc0[rt]=t3;
        rev[rt]^=1;
        return;
    }
    pushdown(rt,l,r);
    int mid=(l+r)>>1;
    if (R<=mid) revers(L,R,lson);
    else
    if (L>mid) revers(L,R,rson);
    else
    {
        revers(L,R,lson);
        revers(L,R,rson);
    }
    up(rt,l,r);
}
int output(int op,int L,int R,int rt,int l,int r)
{
    if (L==l && r==R){
        if (op==3) return d[rt];
        else  return maxc[rt];
    }
    pushdown(rt,l,r);
    int mid=(l+r)>>1;
    if (L>mid) return output(op,L,R,rson);
    else
    if (R<=mid) return output(op,L,R,lson);
    else
    {
        int ret1=output(op,L,mid,lson);
        int ret2=output(op,mid+1,R,rson);
        if (op==3) return ret1+ret2;
        else{
            int ret=max(ret1,ret2);
            int t1=min(rc[rt<<1],mid-L+1);
            int t2=min(lc[rt<<1|1],R-mid);
            ret=max(ret,t1+t2);
            return ret;
        }
    }
}
int main()
{
    int t,op,a,b;
    scanf("%d",&t);
    while (t--)
    {
        scanf("%d%d",&n,&Q);
        for (int i=1;i<=n;i++) scanf("%d",&A[i]);
        build(1,1,n);
        while (Q--)
        {
            scanf("%d%d%d",&op,&a,&b);
            a++;b++;
            if (op<=1){
                change(op,a,b,1,1,n);
            }
            else
            if (op==2){
                revers(a,b,1,1,n);
            }
            else
            {
                int ans=output(op,a,b,1,1,n);
                printf("%d\n",ans);
            }
        }
    }
    return 0;
}

  

HDU 3397 线段树 双懒惰标记,布布扣,bubuko.com

时间: 2024-10-26 21:52:56

HDU 3397 线段树 双懒惰标记的相关文章

HDU 3397 线段树

WA了好几发...细节颇多,总之写线段树就要写好pushdown和pushup函数 拍了300组数据才找到错误- -||新技能Get #include"cstdio" #include"queue" #include"cmath" #include"stack" #include"iostream" #include"algorithm" #include"cstring&qu

HDU 3397 线段树区间修改

Sequence operation Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 8308    Accepted Submission(s): 2507 Problem Description lxhgww got a sequence contains n characters which are all '0's or '1'

HDU 4553 线段树双关键字区间合并

用两个关键字记录,分别为屌丝时间和女神时间 若屌丝约,更新屌丝时间 若女神约,更新屌丝和女神时间 学习,则两个全部清空 #include "stdio.h" #include "string.h" struct Data { int l,r,x1,x2,l1,l2,r1,r2; }data[400010]; int Max(int a,int b) { if (a<b) return b;else return a; } void build(int l,in

hdu 4893 线段树 --- 也是两个变 类似双标记

http://acm.hdu.edu.cn/showproblem.php?pid=4893 开始的时候,我按双标记,WA了一下午,搞不定,我是用的两个标记add--表示当前结点中有值发生变化,flag,斐波那契的懒惰标记,但是估计是我自己处理的有问题,一直不对 参考了别人的代码,写法还是很不错的,Add变量维护的是,完全变成Fibonacci的时候的和,---回头我再重新写一遍 #include <cstdio> #include <cstring> #include <a

HDU 4902 (线段树)

Problem Nice boat(HDU 4902) 题目大意 维护一个序列,两种操作. 第一种操作,将一段区间[l,r]赋值为x. 第二种操作,将一段区间[l,r]中大于等于x的数与x求gcd. 询问所有操作结束后的序列. 解题分析 用线段树开一个标记same,表示这段区间中的数是否相同,若相同则为该数,否则为-1. 对于第二种操作,对于覆盖区间内的same不为-1的子区间暴力修改. 虽然时限有15s,但貌似跑得挺快的,只用了1s,不知是数据水还是什么缘故. 参考程序 1 #include

HDU 4893 线段树裸题

Wow! Such Sequence! Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 2512    Accepted Submission(s): 751 Problem Description Recently, Doge got a funny birthday present from his new friend, Pro

HDU 4902 线段树||暴力

给定一个序列,两种操作 1:把一段变成x. 2:把一段每个数字,如果他大于x,就变成他和x的gcd,求变换完后,最后的序列. 线段树解法:用lazy标记下即可,优化方法还是很巧妙的, Accepted 4902 515MS 3308K 1941 B C++ #include "stdio.h" #include "string.h" struct node { int l,r,x;// 在叶子节点代表值,树节点代表成端更新的lazy操作. }data[400010]

HDU 1698 线段树(区间染色)

Just a Hook Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 16255    Accepted Submission(s): 8089 Problem Description In the game of DotA, Pudge’s meat hook is actually the most horrible thing f

POJ 2777 &amp;&amp; ZOJ 1610 &amp;&amp;HDU 1698 --线段树--区间更新

直接将这3题 放一起了  今天在做线段树的东西 这3个都是区间更新的 查询方式互相不同 反正都可以放到一起吧 直接先上链接了 touch me touch me touch me 关于涉及到区间的修改 -- 区间更新的话 分为 增减 或者 修改 主要就是个 laze 标记 就是延迟更新 对于区间更新的写法 一般是有2种 其一 仔细划分到每个细小的区间    另一 粗略划分 反正 ==我的代码里会给出2种写法 看自己喜好 hdu 1 //线段树 成段更新 ---> 替换 根结点的查询 2 3 #i