zoukankan      html  css  js  c++  java
  • P2572 [SCOI2010]序列操作

    建树的函数不要忘了return!!!

    
    #include<iostream>
    #include<cstdio>
    #define N 100005
    using namespace std;
    int n,m; 
    struct seg
    {
        int l,r;
        int l0,l1;//从左端开始连续0(1)的个数 
    	int r0,r1;//从右端开始连续0(1)的个数 
    	int mx0,mx1;//最多有多少个连续的0(1) 
    	int sum0,sum1;//有多少个0(1) 
        int rev;//取反标志 
    	int c; // 染色 
    	int full;//整个区间填充是1还是0 
    }t[N<<2];//共13个成员 
        
    void rev(int k)//第k个点取反 ,在外层修改了取反标志 
    {
        swap(t[k].l0,t[k].l1);
        swap(t[k].r0,t[k].r1);
        swap(t[k].mx0,t[k].mx1);
        swap(t[k].sum0,t[k].sum1);
        if(t[k].full!=-1)t[k].full^=1;
    }
    
    void color(int k,int v)//第k个点全改成0(1)  
    {
        t[k].rev=0;
        int s=t[k].r-t[k].l+1;
        if(v==0)
        {
           t[k].sum0=t[k].l0=t[k].r0=t[k].mx0=s;
           t[k].sum1=t[k].l1=t[k].r1=t[k].mx1=0;
        }
        else
        {
           t[k].sum0=t[k].l0=t[k].r0=t[k].mx0=0;
           t[k].sum1=t[k].l1=t[k].r1=t[k].mx1=s;
        }
        t[k].full=v;
    }
     
    seg merge(seg a,seg b) //合并子节点更新父节点所有成员 ,返回结构体 
    {
        seg tmp;
    	tmp.l=a.l;tmp.r=b.r;//左右端点 
        tmp.rev=0;tmp.c=-1;
        tmp.l0=a.l0;tmp.l1=a.l1;
        tmp.r0=b.r0;tmp.r1=b.r1;
        
        tmp.mx0=max(a.mx0,b.mx0);//3个取最大 
        tmp.mx1=max(a.mx1,b.mx1);
        tmp.mx0=max(tmp.mx0,a.r0+b.l0);
        tmp.mx1=max(tmp.mx1,a.r1+b.l1);
        
        tmp.sum0=a.sum0+b.sum0;
        tmp.sum1=a.sum1+b.sum1;
        
        if(a.full==0)tmp.l0=a.mx0+b.l0;
        else if(a.full==1)tmp.l1=a.mx1+b.l1;
        if(b.full==0)tmp.r0=b.mx0+a.r0;
        else if(b.full==1)tmp.r1=b.mx1+a.r1;
        //修改成员full 
        if(a.full==b.full)
           tmp.full=a.full;
        else tmp.full=-1;
        
        return tmp;
    }
    
    void pushup(int k)//利用子节点更新父节点 
    {
        t[k]=merge(t[k<<1],t[k<<1|1]);
    }
    
    //下传有什么用 。把父节点的信息下传给子节点 
    void pushdown(int k)
    {
        if(t[k].l==t[k].r)return;
        if(t[k].c!=-1)
        {
            t[k<<1].c=t[k<<1|1].c=t[k].c;
            color(k<<1,t[k].c);color(k<<1|1,t[k].c);
            t[k].c=-1;//??? 
        }
        if(t[k].rev)
        {
            t[k<<1].rev^=1;
            t[k<<1|1].rev^=1;
            rev(k<<1);rev(k<<1|1);
            t[k].rev=0;
        }
    }
    void build(int k,int l,int r)
    {
        t[k].l=l;t[k].r=r;
        t[k].c=-1;
        if(l==r)
        {
            scanf("%d",&t[k].full);//001 
            if(t[k].full)
            {t[k].l1=t[k].r1=t[k].mx1=t[k].sum1=1;}
            else
            {t[k].l0=t[k].r0=t[k].mx0=t[k].sum0=1;}
            return;
        }
        int mid=(l+r)>>1;
        build(k<<1,l,mid);
    	build(k<<1|1,mid+1,r);
        pushup(k);//更新父节点 
    }
    
    //修改一个区间的值时,要先向下更新子节点,再向上更新父节点  
    void change(int k,int x,int y,int v)
    {
        pushdown(k);//先更新子节点 
        int l=t[k].l,r=t[k].r;
        if(l==x&&r==y)
        {
            color(k,v);
            t[k].c=v;
            return;
        }
        int mid=(l+r)>>1;
        if(mid>=y)change(k<<1,x,y,v);
        else if(mid<x)change(k<<1|1,x,y,v);
        else
        {
            change(k<<1,x,mid,v);
            change(k<<1|1,mid+1,y,v);
        }
        pushup(k);//更新父节点 
    }
    
    //修改一个区间,全取反 ,要先向下更新子节点,再向上更新父节点   
    void rever(int k,int x,int y)
    {
        pushdown(k);
        int l=t[k].l,r=t[k].r;
        if(l==x&&r==y)
        {
            rev(k);
            t[k].rev=1;
            return;
        }
        int mid=(l+r)>>1;
        if(mid>=y)rever(k<<1,x,y);
        else if(mid<x)rever(k<<1|1,x,y);
        else
        {
            rever(k<<1,x,mid);
            rever(k<<1|1,mid+1,y);
        }
        pushup(k);
    }
    
    //查询区间内最大有多少连续的1 ,因为要用到子节点的信息,所以先向下更新,没有更新子节点的信息,所以不用向上更新 
    seg ask(int k,int x,int y)
    {
        pushdown(k);
        int l=t[k].l,r=t[k].r;
        if(l==x&&y==r)return t[k];
        int mid=(l+r)>>1;
        if(mid>=y)return ask(k<<1,x,y);
        else if(mid<x)return ask(k<<1|1,x,y);
        else return merge(ask(k<<1,x,mid),ask(k<<1|1,mid+1,y));
    }
    
    //统计区间内1的总数 
    int asksum(int k,int x,int y)
    {
        pushdown(k);
        int l=t[k].l,r=t[k].r;
        if(l==x&&y==r)return t[k].sum1;//为什么不是落在区间内 
        int mid=(l+r)>>1;
        if(mid>=y)return asksum(k<<1,x,y);
        else if(mid<x)return asksum(k<<1|1,x,y);
        else return asksum(k<<1,x,mid)+asksum(k<<1|1,mid+1,y);
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        build(1,1,n);
        for(int i=1;i<=m;i++)
        {
            int f,x,y;
            scanf("%d%d%d",&f,&x,&y);
            x++;y++; 
            switch(f)
            {
                case 0:change(1,x,y,0);break;
                case 1:change(1,x,y,1);break;
                case 2:rever(1,x,y);break;
                case 3:printf("%d
    ",asksum(1,x,y));break;
                case 4:printf("%d
    ",ask(1,x,y).mx1);break;
            }
        }
        return 0;
    }
    
  • 相关阅读:
    Php开发学习---言简意赅,内含视频教程
    决策树剪枝的三种方法
    梯度弥散与梯度爆炸
    算法岗面试题积累一
    《转》从系统和代码实现角度解析TensorFlow的内部实现原理 | 深度
    算法复习-全排列的非递归和递归实现(含重复元素)
    xgboost使用细节
    pandas Series和dataframe
    python 字符词串和字符串的转换
    (转载)自然语言处理中的Attention Model:是什么及为什么
  • 原文地址:https://www.cnblogs.com/ShineEternal/p/11377059.html
Copyright © 2011-2022 走看看