zoukankan      html  css  js  c++  java
  • HDU 3397 Sequence operation (区间合并,操作比较多)

      费了我一天半的时间,到处debug,后来才发现,主要是建树的时候只在叶子节点对lazy1和lazy2进行初始化了,父节点都没初始化。。。晕。

      具体见代码吧。

    #include <iostream>
    #include <stdio.h>
    #include <algorithm>
    #define lson rt<<1,L,mid
    #define rson rt<<1|1,mid+1,R
    /*
    用两个lazy标记,lazy1标记01覆盖,lazy2标记异或(即取反)。
    如果在lazy1标记之前,就已经有lazy2异或标记了,那么我们就可以直接去掉lazy2标记(赋值为0),直接进行置01标记;
    如果在lazy2异或标记之前,就有01标记了,那么就需要处理一下,即对lazy1进行异或。
    
    具体还是见代码吧,主要是操作繁琐了点
    */
    using namespace std;
    const int maxn=100005;
    int t,n,m;
    
    struct Node{
        int lsum[2],rsum[2],msum[2];  //统计0/1的左连续的个数,右连续的个数,最大的连续个数
        int num[2];   //统计0/1的个数
        int lazy1;    //标记01覆盖
        int lazy2;    //标记取反
        int len;      //区间长度
    }tree[maxn<<2];
    
    
    void pushUp(Node &rt,Node &ls,Node &rs){
        rt.lsum[0]=ls.lsum[0];rt.rsum[0]=rs.rsum[0];
        rt.lsum[1]=ls.lsum[1];rt.rsum[1]=rs.rsum[1];
    
        rt.num[0]=ls.num[0]+rs.num[0];
        rt.num[1]=ls.num[1]+rs.num[1];
        if(ls.lsum[0]==ls.len)
                rt.lsum[0]+=rs.lsum[0];
        if(rs.rsum[0]==rs.len)
                rt.rsum[0]+=ls.rsum[0];
        rt.msum[0]=ls.rsum[0]+rs.lsum[0];
        rt.msum[0]=max(rt.msum[0],max(ls.msum[0],rs.msum[0]));
    
        if(ls.lsum[1]==ls.len)
                rt.lsum[1]+=rs.lsum[1];
        if(rs.rsum[1]==rs.len)
                rt.rsum[1]+=ls.rsum[1];
        rt.msum[1]=ls.rsum[1]+rs.lsum[1];
        rt.msum[1]=max(rt.msum[1],max(ls.msum[1],rs.msum[1]));
    }
    void changexor(Node &rt){
        if(rt.lazy1!=-1)
            rt.lazy1^=1;    //如果之前有01标记,那么就对01标记异或一下即可
        else
            rt.lazy2^=1;    //否则对取反标记异或
        swap(rt.num[1],rt.num[0]);
        swap(rt.lsum[1],rt.lsum[0]);
        swap(rt.rsum[1],rt.rsum[0]);
        swap(rt.msum[1],rt.msum[0]);
    }
    
    void pushDown(Node &rt,Node &ls,Node &rs,int m){
        /*
          因为lazy1和lazy2标记只能同时存在一个,所以只需对其中一个操作即可
          如果现有标记为lazy1,若进行取反,对lazy1异或即可,即原本全部覆盖成0的变成1,原本为1的变成0,不需对lazy2异或;
              若进行覆盖操作,那么直接对lazy1修改。
          如果现有标记为lazy2,若进行覆盖操作,那么lazy2直接变为0,;若进行取反操作,则对lazy2进行异或
        */
        if(rt.lazy1!=-1){
            //01覆盖区间
            ls.lazy1=rs.lazy1=rt.lazy1;
            rs.lazy2=ls.lazy2=0;
            ls.num[rt.lazy1]=ls.lsum[rt.lazy1]=ls.rsum[rt.lazy1]=ls.msum[rt.lazy1]=m-m/2;
            ls.num[!rt.lazy1]=ls.lsum[!rt.lazy1]=ls.rsum[!rt.lazy1]=ls.msum[!rt.lazy1]=0;
            rs.num[rt.lazy1]=rs.lsum[rt.lazy1]=rs.rsum[rt.lazy1]=rs.msum[rt.lazy1]=m/2;
            rs.num[!rt.lazy1]=rs.lsum[!rt.lazy1]=rs.rsum[!rt.lazy1]=rs.msum[!rt.lazy1]=0;
            rt.lazy1=-1;
        }
        else if(rt.lazy2){
            //对区间取反
            rt.lazy2=0;
            changexor(ls);
            changexor(rs);
        }
    }
    void build(int rt,int L,int R){
        tree[rt].len=R-L+1;
        tree[rt].lazy1=-1;  //build时都忘记初始化了啊
        tree[rt].lazy2=0;   //build时都忘记初始化了啊
        if(L==R){
            int v;
            scanf("%d",&v);
            tree[rt].lsum[v]=tree[rt].rsum[v]=tree[rt].msum[v]=1;
            tree[rt].lsum[!v]=tree[rt].rsum[!v]=tree[rt].msum[!v]=0;
            tree[rt].num[v]=1;
            tree[rt].num[!v]=0;
            tree[rt].lazy1=-1;
            return;
        }
        int mid=(L+R)>>1;
        build(lson);
        build(rson);
        pushUp(tree[rt],tree[rt<<1],tree[rt<<1|1]);
    }
    
    //进行操作01覆盖区间
    void update(int rt,int L,int R,int l,int r,int c){
        if(l<=L&&R<=r){
            tree[rt].lazy2=0;  //之前的取反操作就无效了
            tree[rt].num[c]=tree[rt].lsum[c]=tree[rt].rsum[c]=tree[rt].msum[c]=(R-L+1);
            tree[rt].num[!c]=tree[rt].lsum[!c]=tree[rt].rsum[!c]=tree[rt].msum[!c]=0;
            tree[rt].lazy1=c;
            return;
        }
        pushDown(tree[rt],tree[rt<<1],tree[rt<<1|1],R-L+1);
        int mid=(L+R)>>1;
        if(l<=mid)
            update(lson,l,r,c);
        if(r>mid)
            update(rson,l,r,c);
        pushUp(tree[rt],tree[rt<<1],tree[rt<<1|1]);
    }
    //进行取反操作
    void updatexor(int rt,int L,int R,int l,int r){
        if(l<=L&&R<=r){
            if(tree[rt].lazy1!=-1)
                tree[rt].lazy1^=1;  //如果之前有01标记,则要进行处理,对其异或,即取反
            else
                tree[rt].lazy2^=1;
            //只要将值互换一下即可
            swap(tree[rt].num[1],tree[rt].num[0]);
            swap(tree[rt].lsum[1],tree[rt].lsum[0]);
            swap(tree[rt].rsum[1],tree[rt].rsum[0]);
            swap(tree[rt].msum[1],tree[rt].msum[0]);
            return;
        }
        pushDown(tree[rt],tree[rt<<1],tree[rt<<1|1],R-L+1);
        int mid=(L+R)>>1;
        if(l<=mid)
            updatexor(lson,l,r);
        if(r>mid)
            updatexor(rson,l,r);
        pushUp(tree[rt],tree[rt<<1],tree[rt<<1|1]);
    }
    //查询时,类型设为Node,进行节点合并,这样就方便好多
    Node query(int rt,int L,int R,int l,int r){
        if(l<=L&&R<=r){
            return tree[rt];
        }
        pushDown(tree[rt],tree[rt<<1],tree[rt<<1|1],R-L+1);
        int mid=(L+R)>>1;
        Node tmp,r1,r2;
        if(r<=mid)
            tmp=query(lson,l,r);
        else if(l>mid)
            tmp=query(rson,l,r);
        else{
            r1=query(lson,l,mid);
            r2=query(rson,mid+1,r);
            tmp.len=r1.len+r2.len;
            pushUp(tmp,r1,r2);  //将节点r1和r2合并成tmp
        }
        return tmp;
    }
    
    int main()
    {
        int op,a,b;
        Node ans;
        scanf("%d",&t);
        while(t--){
            scanf("%d%d",&n,&m);
            build(1,1,n);
            for(int i=1;i<=m;i++){
                scanf("%d%d%d",&op,&a,&b);
                a++;b++;
                if(op<=1)
                    update(1,1,n,a,b,op);
                else if(op==2)
                    updatexor(1,1,n,a,b);
                else{
                    ans=query(1,1,n,a,b);
                    if(op==3)
                        printf("%d
    ",ans.num[1]);
                    else
                        printf("%d
    ",ans.msum[1]);
                }
            }
        }
        return 0;
    }
  • 相关阅读:
    [编]使用AutoCompleteExtender实现文本框自动匹配
    C#中的泛型
    Adapter模式
    .Net 项目代码风格要求
    Asp.Net Ajax的两种基本开发模式
    .NET框架
    SQL Server文章目录
    【转】prometheus数据上报方式pushgateway
    Operation is not valid due to the current state of the object
    lisp 笔记 闭包
  • 原文地址:https://www.cnblogs.com/chenxiwenruo/p/3417182.html
Copyright © 2011-2022 走看看