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

    2421 序列操作

    http://codevs.cn/problem/2421/

    2010年省队选拔赛四川

     
    题目描述 Description

    lxhgww最近收到了一个01序列,序列里面包含了n个数,这些数要么是0,要么是1,现在对于这个序列有五种变换操作和询问操作:

    0 a b 把[a, b]区间内的所有数全变成0

    1 a b 把[a, b]区间内的所有数全变成1

    2 a b 把[a,b]区间内的所有数全部取反,也就是说把所有的0变成1,把所有的1变成0

    3 a b 询问[a, b]区间内总共有多少个1

    4 a b 询问[a, b]区间内最多有多少个连续的1

    对于每一种询问操作,lxhgww都需要给出回答,聪明的程序员们,你们能帮助他吗?

    输入描述 Input Description

       输入数据第一行包括2个数,n和m,分别表示序列的长度和操作数目

       第二行包括n个数,表示序列的初始状态

       接下来m行,每行3个数,op, a, b,(0<=op<=4,0<=a<=b<n)表示对于区间[a, b]执行标号为op的操作

    输出描述 Output Description

       对于每一个询问操作,输出一行,包括1个数,表示其对应的答案

    样例输入 Sample Input

       10 10

       0 0 0 1 1 0 1 0 1 1

       1 0 2

       3 0 5

       2 2 2

       4 0 4

       0 3 6

       2 3 7

       4 2 8

       1 0 5

       0 5 6

       3 3 9

    样例输出 Sample Output

       5

       2

       6

       5

    数据范围及提示 Data Size & Hint

       对于30%的数据,1<=n, m<=1000

       对于100%的数据,1<=n, m<=100000

    线段树

    题目AC四步走

    第一步:TLE 50分

    代码中线段树均使用2n空间方法建树

    维护信息:

    0的个数sum_0,1的个数sum_1,  连续的0的个数con_0,  连续的1的个数con_1;
    左端点连续0的个数l_0,  右端点连续0的个数r_0,  左端点连续1的个数l_1,  右端点连续1的个数r_1;
    懒标记f,f=-1表示区间无标记,=0表示区间有一个全部更新为0的标记没有下穿,=1同理;

    操作0,1:线段树基本的区间修改

    操作2:可以一直递归到一个区间都是0或都是1时在操作,也相当于区间修改

    操作3:线段树基本的区间查询

    操作4:类似于求GSS的查询过程,在更新l_0,r_0,l_1,r_1时稍有不同,要先判断是否包括整个左右子区间

    TLE 原因:多余的标记下传

    1、标记下穿时,没有必要保证子节点的标记也下传了,因为有效标记只有两种,0,1,而且是对整个区间完全覆盖,所以多个标记只有最后一个有效

    2、区间取反时,没有必要保证本区间标记下传,因为如果原来区间标记是0,意思是子区间要变为0,区间取反后区间标记是1,意思是子区间要变为1,与原来标记是什么无关。

    第二步:AC 100分,总时间耗费: 881ms    总内存耗费: 11 MB

    将导致TLE的3行删去

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    struct node
    {
        int l,r;
        int sum_0,sum_1,con_0,con_1,sum;
        int l_0,r_0,l_1,r_1;
        int f;
    }e[200001];
    int n,m,cnt,x,p,a,b,anss;
    void change(int,int);
    inline void up(int k)
    {
        int l=k+1,r=k+e[k+1].sum*2;
        e[k].sum_0=e[l].sum_0+e[r].sum_0;
        e[k].sum_1=e[l].sum_1+e[r].sum_1;
        e[k].con_0=max(max(e[l].con_0,e[r].con_0),e[l].r_0+e[r].l_0);
        e[k].con_1=max(max(e[l].con_1,e[r].con_1),e[l].r_1+e[r].l_1);
        if(e[l].con_0==e[l].sum) e[k].l_0=e[l].sum+e[r].l_0;
        else e[k].l_0=e[l].l_0;
        if(e[r].con_0==e[r].sum) e[k].r_0=e[r].sum+e[l].r_0;
        else e[k].r_0=e[r].r_0;
        if(e[l].con_1==e[l].sum) e[k].l_1=e[l].sum+e[r].l_1;
        else e[k].l_1=e[l].l_1;
        if(e[r].con_1==e[r].sum) e[k].r_1=e[r].sum+e[l].r_1;
        else e[k].r_1=e[r].r_1;
    }
    inline void all_0(int k)
    {
        e[k].sum_0=e[k].con_0=e[k].l_0=e[k].r_0=e[k].sum;
        e[k].sum_1=e[k].con_1=e[k].l_1=e[k].r_1=0;
    }
    inline void all_1(int k)
    {
        e[k].sum_1=e[k].con_1=e[k].l_1=e[k].r_1=e[k].sum;
        e[k].sum_0=e[k].con_0=e[k].l_0=e[k].r_0=0;
    }
    inline void down(int k)
    {
        if(e[k].l==e[k].r) return;
        int l=k+1,r=k+e[k+1].sum*2;
        //if(e[l].f!=-1) down(l); TLE
        //if(e[r].f!=-1) down(r); TLE
        if(!e[k].f)
        {
            all_0(l);all_0(r);
            e[l].f=e[r].f=0;
        }
        else
        {
            all_1(l);all_1(r);
            e[l].f=e[r].f=1;
        }
        e[k].f=-1;
    }
    inline void judge(int k)
    {
        //if(e[k].f!=-1) down(k); TLE
        if(e[k].sum_0==e[k].sum) 
        {
            all_1(k);
            e[k].f=1;
        }
        else if(e[k].sum_1==e[k].sum) 
        {
            all_0(k);
            e[k].f=0;
        }
        else
        {            
            judge(k+1);
            judge(k+e[k+1].sum*2);        
        }
        if(e[k].f!=-1) down(k);
        if(e[k].l!=e[k].r) up(k);
    }
    inline void change(int k,int g)
    {
        if(e[k].l>=a&&e[k].r<=b)
        {
            if(!g)        { all_0(k); e[k].f=0; }
            else if(g==1) { all_1(k); e[k].f=1; }
            else if(g==2) { judge(k); }
            else if(g==3) { anss+=e[k].sum_1; }
            return;
        }
        if(e[k].f!=-1) down(k);
        int mid=e[k].l+e[k].r>>1;
        if(a<=mid) change(k+1,g);
        if(b>mid) change(k+e[k+1].sum*2,g);
        up(k);
    }
    inline void build(int l,int r)
    {
        cnt++;
        int h=cnt;
        e[cnt].l=l;e[cnt].r=r;
        e[cnt].sum=r-l+1;
        e[cnt].f=-1;
        if(l==r)
        {
            scanf("%d",&x);
            if(x) { e[cnt].sum_1=e[cnt].con_1=e[cnt].l_1=e[cnt].r_1=1; }
            else  { e[cnt].sum_0=e[cnt].con_0=e[cnt].l_0=e[cnt].r_0=1; }
            return;
        }
        int mid=l+r>>1;
        build(l,mid);build(mid+1,r);
        up(h);
    }
    inline void ask(int k,int & ans,int & ans_l,int & ans_r)
    {
        int l=k+1,r=k+e[k+1].sum*2;
        if(e[k].l>=a&&e[k].r<=b)
        {
            ans=e[k].con_1;
            ans_l=e[k].l_1;
            ans_r=e[k].r_1;
            return;
        }
        if(e[k].f!=-1) down(k);
        int mid=e[k].l+e[k].r>>1;
        if(b<=mid) ask(l,ans,ans_l,ans_r);
        else if(a>mid) ask(r,ans,ans_l,ans_r);
        else
        {
            int lch_ans,lch_l_1,lch_r_1,rch_ans,rch_l_1,rch_r_1;
            ask(l,lch_ans,lch_l_1,lch_r_1);
            ask(r,rch_ans,rch_l_1,rch_r_1);
            ans=max(lch_ans,rch_ans);
            ans=max(ans,lch_r_1+rch_l_1);
            if(e[l].con_1==e[l].sum) ans_l=max(lch_l_1,e[l].sum+rch_l_1);
            else ans_l=lch_l_1;
            if(e[r].con_1==e[r].sum) ans_r=max(rch_r_1,e[r].sum+lch_r_1);
            else ans_r=rch_r_1;
        }
    } 
    int main()
    {
        scanf("%d%d",&n,&m);
        build(0,n-1);
        int ans,ans_l,ans_r;
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%d",&p,&a,&b);
            switch(p)
            {
                case 0:change(1,0);break;
                case 1:change(1,1);break;
                case 2:change(1,2);break;
                case 3:anss=0,change(1,3),printf("%d
    ",anss);break;
                case 4:ask(1,ans,ans_l,ans_r),printf("%d
    ",ans);
            }
        }
    }              
    View Code

    第三步:去掉多余信息    总时间耗费: 683ms  总内存耗费: 6 MB

    老师讲课时提到要维护0的信息,是因为操作2可以直接交换0和1的信息来完成

    但自己做的时候操作2不是这样实现的,所以0的信息不用维护

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    struct node
    {
        int l,r;
        int sum_1,con_1,sum;
        int l_1,r_1;
        int f;
    }e[200001];
    int n,m,cnt,x,p,a,b,anss;
    void change(int,int);
    inline void up(int k)
    {
        int l=k+1,r=k+e[k+1].sum*2;
        e[k].sum_1=e[l].sum_1+e[r].sum_1;
        e[k].con_1=max(max(e[l].con_1,e[r].con_1),e[l].r_1+e[r].l_1);
        if(e[l].con_1==e[l].sum) e[k].l_1=e[l].sum+e[r].l_1;
        else e[k].l_1=e[l].l_1;
        if(e[r].con_1==e[r].sum) e[k].r_1=e[r].sum+e[l].r_1;
        else e[k].r_1=e[r].r_1;
    }
    inline void all_0(int k)
    {
        e[k].sum_1=e[k].con_1=e[k].l_1=e[k].r_1=0;
    }
    inline void all_1(int k)
    {
        e[k].sum_1=e[k].con_1=e[k].l_1=e[k].r_1=e[k].sum;
    }
    inline void down(int k)
    {
        if(e[k].l==e[k].r) return;
        int l=k+1,r=k+e[k+1].sum*2;
        if(!e[k].f)
        {
            all_0(l);all_0(r);
            e[l].f=e[r].f=0;
        }
        else
        {
            all_1(l);all_1(r);
            e[l].f=e[r].f=1;
        }
        e[k].f=-1;
    }
    inline void judge(int k)
    {
        if(!e[k].sum_1) 
        {
            all_1(k);
            e[k].f=1;
        }
        else if(e[k].sum_1==e[k].sum) 
        {
            all_0(k);
            e[k].f=0;
        }
        else
        {    
            judge(k+1);
            judge(k+e[k+1].sum*2);        
        }
        if(e[k].f!=-1) down(k);
        if(e[k].l!=e[k].r) up(k);
    }
    inline void change(int k,int g)
    {
        if(e[k].l>=a&&e[k].r<=b)
        {
            if(!g)        { all_0(k); e[k].f=0; }
            else if(g==1) { all_1(k); e[k].f=1; }
            else if(g==2) { judge(k); }
            else if(g==3) { anss+=e[k].sum_1; }
            return;
        }
        if(e[k].f!=-1) down(k);
        int mid=e[k].l+e[k].r>>1;
        if(a<=mid) change(k+1,g);
        if(b>mid) change(k+e[k+1].sum*2,g);
        up(k);
    }
    inline void build(int l,int r)
    {
        cnt++;
        int h=cnt;
        e[cnt].l=l;e[cnt].r=r;
        e[cnt].sum=r-l+1;
        e[cnt].f=-1;
        if(l==r)
        {
            scanf("%d",&x);
            if(x) { e[cnt].sum_1=e[cnt].con_1=e[cnt].l_1=e[cnt].r_1=1; }
            return;
        }
        int mid=l+r>>1;
        build(l,mid);build(mid+1,r);
        up(h);
    }
    inline void ask(int k,int & ans,int & ans_l,int & ans_r)
    {
        int l=k+1,r=k+e[k+1].sum*2;
        if(e[k].l>=a&&e[k].r<=b)
        {
            ans=e[k].con_1;
            ans_l=e[k].l_1;
            ans_r=e[k].r_1;
            return;
        }
        if(e[k].f!=-1) down(k);
        int mid=e[k].l+e[k].r>>1;
        if(b<=mid) ask(l,ans,ans_l,ans_r);
        else if(a>mid) ask(r,ans,ans_l,ans_r);
        else
        {
            int lch_ans,lch_l_1,lch_r_1,rch_ans,rch_l_1,rch_r_1;
            ask(l,lch_ans,lch_l_1,lch_r_1);
            ask(r,rch_ans,rch_l_1,rch_r_1);
            ans=max(lch_ans,rch_ans);
            ans=max(ans,lch_r_1+rch_l_1);
            if(e[l].con_1==e[l].sum) ans_l=max(lch_l_1,e[l].sum+rch_l_1);
            else ans_l=lch_l_1;
            if(e[r].con_1==e[r].sum) ans_r=max(rch_r_1,e[r].sum+lch_r_1);
            else ans_r=rch_r_1;
        }
    } 
    int main()
    {
        scanf("%d%d",&n,&m);
        build(0,n-1);
        int ans,ans_l,ans_r;
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%d",&p,&a,&b);
            switch(p)
            {
                case 0:change(1,0);break;
                case 1:change(1,1);break;
                case 2:change(1,2);break;
                case 3:anss=0,change(1,3),printf("%d
    ",anss);break;
                case 4:ask(1,ans,ans_l,ans_r),printf("%d
    ",ans);
            }
        }
    }  
    View Code

    第四步:换方法   操作2按上面说的实现

    然而代码越改越长,空间越勇越大,时间越用越多,却并没有AC

    这道题耗了1天了,时间不允许了,日后再改吧

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    struct node
    {
        int l,r;
        int sum_0,sum_1,con_0,con_1,sum;
        int l_0,r_0,l_1,r_1;
        int f;
        bool f2;
    }e[200001];
    int n,m,cnt,x,p,a,b,anss;
    void change(int,int);
    inline void up(int k)
    {
        int l=k+1,r=k+e[k+1].sum*2;
        e[k].sum_0=e[l].sum_0+e[r].sum_0;
        e[k].sum_1=e[l].sum_1+e[r].sum_1;
        e[k].con_0=max(max(e[l].con_0,e[r].con_0),e[l].r_0+e[r].l_0);
        e[k].con_1=max(max(e[l].con_1,e[r].con_1),e[l].r_1+e[r].l_1);
        if(e[l].con_0==e[l].sum) e[k].l_0=e[l].sum+e[r].l_0;
        else e[k].l_0=e[l].l_0;
        if(e[r].con_0==e[r].sum) e[k].r_0=e[r].sum+e[l].r_0;
        else e[k].r_0=e[r].r_0;
        if(e[l].con_1==e[l].sum) e[k].l_1=e[l].sum+e[r].l_1;
        else e[k].l_1=e[l].l_1;
        if(e[r].con_1==e[r].sum) e[k].r_1=e[r].sum+e[l].r_1;
        else e[k].r_1=e[r].r_1;
    }
    inline void all_0(int k)
    {
        e[k].sum_0=e[k].con_0=e[k].l_0=e[k].r_0=e[k].sum;
        e[k].sum_1=e[k].con_1=e[k].l_1=e[k].r_1=0;
    }
    inline void all_1(int k)
    {
        e[k].sum_1=e[k].con_1=e[k].l_1=e[k].r_1=e[k].sum;
        e[k].sum_0=e[k].con_0=e[k].l_0=e[k].r_0=0;
    }
    inline void judge(int k)
    {
        swap(e[k].con_0,e[k].con_1);
        swap(e[k].sum_0,e[k].sum_1);
        swap(e[k].l_0,e[k].l_1);
        swap(e[k].r_0,e[k].r_1);
        if(e[k].l!=e[k].r) {e[k].f=2;e[k].f2=true;}
    }
    void ww(int l)
    {
            if(e[l].l==e[l].r) judge(l);
            else if(e[l].f==0) {e[l].f=1;e[l].f2=false;}
            else if(e[l].f==1) {e[l].f=0;e[l].f2=false;}
            else if(e[l].f==2) e[l].f=-1;
            else                judge(l);
    }
    inline void down(int k)
    {
        if(e[k].l==e[k].r) return;
        int l=k+1,r=k+e[k+1].sum*2;
        if(!e[k].f)
        {
            all_0(l);all_0(r);
            if(e[l].l!=e[l].r) 
            {
                e[l].f=e[r].f=0;
                e[l].f2=e[r].f2=true;
            }
            
        }
        else if(e[k].f==1)
        {
            all_1(l);all_1(r);
            if(e[k].l!=e[k].r) 
            {
                e[l].f=e[r].f=1;
                e[r].f2=e[l].f2=true;
            }
        
        }
        else
        {        
            ww(l);
            ww(r);
            if(e[k].l!=e[k].r) up(k);
        } 
        e[k].f=-1;
    }
    inline int mm(int k)
    {
        if(e[k].f==-1) return e[k].sum_1;
        if(e[k].f2==true) return e[k].sum_1;
        if(e[k].f==0) return 0;
        if(e[k].f==1) return e[k].sum;
        if(e[k].f==2) return e[k].sum_0;
    }
    inline void change(int k,int g)
    {
        if(e[k].l>=a&&e[k].r<=b)
        {
            if(!g) 
            { 
                all_0(k); 
                if(e[k].l!=e[k].r)  e[k].f=0; 
            }
            else if(g==1) 
            { 
                all_1(k); 
                if(e[k].l!=e[k].r) e[k].f=1; 
            }
            else if(g==2) { ww(k); }
            else if(g==3) { anss+=mm(k); }
            return;
        }
        if(e[k].f!=-1) down(k);
        int mid=e[k].l+e[k].r>>1;
        if(a<=mid) change(k+1,g);
        if(b>mid) change(k+e[k+1].sum*2,g);
        up(k);
    }
    inline void build(int l,int r)
    {
        cnt++;
        int h=cnt;
        e[cnt].l=l;e[cnt].r=r;
        e[cnt].sum=r-l+1;
        e[cnt].f=-1;
        e[cnt].f2=true;
        if(l==r)
        {
            scanf("%d",&x);
            if(x) { e[cnt].sum_1=e[cnt].con_1=e[cnt].l_1=e[cnt].r_1=1; }
            else { e[cnt].sum_0=e[cnt].con_0=e[cnt].l_0=e[cnt].r_0=1; }
            return;
        }
        int mid=l+r>>1;
        build(l,mid);build(mid+1,r);
        up(h);
    }
    inline void ask(int k,int & ans,int & ans_l,int & ans_r)
    {
        int l=k+1,r=k+e[k+1].sum*2;
        if(e[k].l>=a&&e[k].r<=b)
        {
            if(e[k].f2==true)
            {
                ans=e[k].con_1;
                ans_l=e[k].l_1;
                ans_r=e[k].r_1;            
            }
            else
            {
                ans=e[k].con_0;
                ans_l=e[k].l_0;
                ans_r=e[k].r_0;    
            }
            return;
        }
        if(e[k].f!=-1) down(k);
        int mid=e[k].l+e[k].r>>1;
        if(b<=mid) ask(l,ans,ans_l,ans_r);
        else if(a>mid) ask(r,ans,ans_l,ans_r);
        else
        {
            int lch_ans,lch_l_1,lch_r_1,rch_ans,rch_l_1,rch_r_1;
            ask(l,lch_ans,lch_l_1,lch_r_1);
            ask(r,rch_ans,rch_l_1,rch_r_1);
            ans=max(lch_ans,rch_ans);
            ans=max(ans,lch_r_1+rch_l_1);
            if(e[l].con_1==e[l].sum) ans_l=max(lch_l_1,e[l].sum+rch_l_1);
            else ans_l=lch_l_1;
            if(e[r].con_1==e[r].sum) ans_r=max(rch_r_1,e[r].sum+lch_r_1);
            else ans_r=rch_r_1;
        }
    } 
    int main()
    {
        scanf("%d%d",&n,&m);
        build(0,n-1);
        int ans,ans_l,ans_r;
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%d",&p,&a,&b);
            switch(p)
            {
                case 0:change(1,0);break;
                case 1:change(1,1);break;
                case 2:change(1,2);break;
                case 3:anss=0,change(1,3),printf("%d
    ",anss);break;
                case 4:ask(1,ans,ans_l,ans_r),printf("%d
    ",ans);
            }
        }
    }
    错误代码

    第一步中出现的错误

    1、第一次提交RE

    2、第二次提交10分,找出RE的错误:down函数里区间标记下传时,没有判断是否到了叶子节点。因为2*n的空间建树,没有节点浪费,但也没有了多余的节点,4*空间建树可以不用判断

    3、第三次提交10分,找出部分错误:down函数里区间标记下传时,只更改了子区间的0,1信息,忘了更改懒标记

    4、第四次提交TLE50分,找出所有错误:judge函数区间取反时,

       ①没有在每次取反后标记下传,

         如果本区间全是0或1,当然要下传标记。

         如果本区间不全是0或1,那区间没有标记,就不需要下穿,又因为没有标记是-1,下传会导致错误,所以 ③要先判断是否需要下传标记

      ②没有对区间修改后的区间信息合并,线段树的修改操作改完要合并信息,又因为2*n的空间建树,所以要 ④先判断是否是叶子节点再合并。change函数里不需要判断叶子节点,是因为到达的叶子节点一定属于操作区间,在合并之前会return

    第四步做了一上午,交了10遍,全是10分,放弃,O| ̄|_

    错误全部集中在down、和取反两个函数里,而down函数只写过求和和最大值的标记,取反函数第一次写,其余函数以前写过,没有错误

  • 相关阅读:
    解决PHP下打开phpMyAdmin出现403错误 Jimmy
    SQL Server连接中三个常见的错误分析
    CD唱片格式知识
    ehlib的DBGridEh控件中使用过滤功能的方法
    TransactSQL MSDN入口
    发烧音响网站大全
    Transact SQL 语 句 功 能
    wwFilterDialog 取得條件
    器材价格 参考用
    phpadmin.config设定
  • 原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/6362729.html
Copyright © 2011-2022 走看看