HDU-3397 线段树+区间合并

Sequence operation


                                                                   Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
                                                                                            Total Submission(s): 8068    Accepted Submission(s): 2416


Problem Description
lxhgww got a sequence contains n characters which are all '0's or '1's.
We have five operations here:
Change operations:
0 a b change all characters into '0's in [a , b]
1 a b change all characters into '1's in [a , b]
2 a b change all '0's into '1's and change all '1's into '0's in [a, b]
Output operations:
3 a b output the number of '1's in [a, b]
4 a b output the length of the longest continuous '1' string in [a , b]
 

Input
T(T<=10) in the first line is the case number.
Each case has two integers in the first line: n and m (1 <= n , m <= 100000).
The next line contains n characters, '0' or '1' separated by spaces.
Then m lines are the operations:
op a b: 0 <= op <= 4 , 0 <= a <= b < n.
 

Output
For each output operation , output the result.
 

Sample Input
  
  
1 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
 

Author
lxhgww&&shǎ崽
 

Source
 


题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=3397


总结:

  好久没写线段树,最近想复习一下,就找了这道以前觉得最复杂的区间合并来练手,上次做这道题还是一年半之前的8月集训,翻翻当时HDU上的记录,这道题整整调了3天。当时对pushdown和pushup这两个操作的理解还没有到位,两种标记处理的很拙劣。现在写线段树的境界有所提高,拿出来重新做,结果还是WA了4遍才过,所以写下这篇博客,记录一下这次错的几个地方:

  (1)第一个,翻转操作标记只是置1,忘记了偶数次翻转的抵消;

  (2)第二个,手残,区间合并的一个右边区间的左边连续1个数llb打成rrb,比赛的话写完代码一定要仔细查一遍;

  (3)第三个,区间合并是有条件的,忽略了mid必须在[a,b]之间的判断;

  (4)第四个,一个操作参数2打成3,原因是这题操作标签是0~4,印象中成了1~5,检查代码各种感觉不会错的细小的地方也要想一下!


AC代码:

  最后附上这次写的姿势比较优美的代码:

  

import java.io.*;

public class Main {
    static StreamTokenizer in=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
    static int nextInt() throws IOException    
    {  
        in.nextToken();    
        return (int)in.nval;     
    }
    static PrintWriter out=new PrintWriter(new OutputStreamWriter(System.out));
    static int T,n,m,a,b,op,maxn=100000;
    static int[] aa=new int[maxn];
    static int[] ss=new int[maxn<<2];
    static int[] lz=new int[maxn<<2];
    static int[] re=new int[maxn<<2];
    static int[] lla=new int[maxn<<2];
    static int[] rra=new int[maxn<<2];
    static int[] mma=new int[maxn<<2];
    static int[] llb=new int[maxn<<2];
    static int[] rrb=new int[maxn<<2];
    static int[] mmb=new int[maxn<<2];
    static void pushup(int k,int l,int r)
    {
        int mid=(l+r)/2;
        ss[k]=ss[k*2+1]+ss[k*2+2];
        lla[k]=lla[k*2+1]+(lla[k*2+1]==mid+1-l?lla[k*2+2]:0);
        rra[k]=rra[k*2+2]+(rra[k*2+2]==r-mid?rra[k*2+1]:0);
        mma[k]=Math.max(rra[k*2+1]+lla[k*2+2],Math.max(mma[k*2+1],mma[k*2+2]));
        llb[k]=llb[k*2+1]+(llb[k*2+1]==mid+1-l?llb[k*2+2]:0);
        rrb[k]=rrb[k*2+2]+(rrb[k*2+2]==r-mid?rrb[k*2+1]:0);
        mmb[k]=Math.max(rrb[k*2+1]+llb[k*2+2],Math.max(mmb[k*2+1],mmb[k*2+2]));
    }
    static void pushdown(int k,int l,int r)
    {
        int mid=(l+r)/2;
        if(lz[k]!=-1)
        {
            up(l,r,k*2+1,l,mid,lz[k]);
            up(l,r,k*2+2,mid+1,r,lz[k]);
        }
        if(re[k]==1)
        {
            up(l,r,k*2+1,l,mid,2);
            up(l,r,k*2+2,mid+1,r,2);
        }
        lz[k]=-1;re[k]=0;
    }
    static void build(int k,int l,int r)
    {
        lz[k]=-1;re[k]=0;
        if(l==r)
        {
            lla[k]=rra[k]=mma[k]=1-aa[l];
            llb[k]=rrb[k]=mmb[k]=ss[k]=aa[l];
            return;
        }
        int mid=(l+r)/2;
        build(k*2+1,l,mid);
        build(k*2+2,mid+1,r);
        pushup(k,l,r);
    }
    static void up(int a,int b,int k,int l,int r,int op)
    {
        if(a>r||b<l) return;
        if(a<=l&&r<=b)
        {
            if(op==2)
            {
                ss[k]=r-l+1-ss[k];
                re[k]=(re[k]+1)%2;
                int c;
                c=lla[k];lla[k]=llb[k];llb[k]=c;
                c=rra[k];rra[k]=rrb[k];rrb[k]=c;
                c=mma[k];mma[k]=mmb[k];mmb[k]=c;
            }
            else
            {
                lz[k]=op;re[k]=0;
                int x=op==0?0:r-l+1;
                ss[k]=llb[k]=rrb[k]=mmb[k]=x;
                lla[k]=rra[k]=mma[k]=r-l+1-x;
            }
        }
        else
        {
            int mid=(l+r)/2;
            pushdown(k,l,r);
            up(a,b,k*2+1,l,mid,op);
            up(a,b,k*2+2,mid+1,r,op);
            pushup(k,l,r);
        }
    }
    static int sum(int a,int b,int k,int l,int r)
    {
        if(a>r||b<l) return 0;
        if(a<=l&&r<=b) return ss[k];
        int mid=(l+r)/2;
        pushdown(k,l,r);
        return sum(a,b,k*2+1,l,mid)+sum(a,b,k*2+2,mid+1,r);
    }
    static int len(int a,int b,int k,int l,int r)
    {
        if(a>r||b<l) return 0;
        if(a<=l&&r<=b) return mmb[k];
        int mid=(l+r)/2,res=0;
        pushdown(k,l,r);
        if(a<=mid&&mid<b)
        {
            res+=Math.min(mid+1-a,rrb[k*2+1]);
            res+=Math.min(b-mid,llb[k*2+2]);
        }
        res=Math.max(res,len(a,b,k*2+1,l,mid));
        res=Math.max(res,len(a,b,k*2+2,mid+1,r));
        return res;
    }

    public static void main(String[] args) throws IOException {
        T=nextInt();
        while(T-->0)
        {
            n=nextInt();m=nextInt();
            for(int i=0;i<n;i++)
                aa[i]=nextInt();
            build(0,0,n-1);
            while(m-->0)
            {
                op=nextInt();
                a=nextInt();b=nextInt();
                if(op==3)
                    out.println(sum(a,b,0,0,n-1));
                else if(op==4)
                    out.println(len(a,b,0,0,n-1));
                else up(a,b,0,0,n-1,op);
            }
            out.flush();
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值