• [SHOI2015]脑洞治疗仪


    [SHOI2015]脑洞治疗仪

    [题目链接]

    链接

    [思路要点]

    较为容易

    线段树维护区间的左边一段连续 (0) 的数量,右边一段 (0) 的数量,除了两边两段 (0) 以外的连续的 (0) 的数量最大值,该区间 (0) 的总数以及该区间是否全部为 (0)

    然后更新很显然,每个都讨论一下

    对于 (0) 操作,就是一次区间赋值

    对于 (1) 操作,首先找到 ([l_0,r_0]) 区间内的 (1) 的个数,然后在 ([l_1,r_1]) 区间内线段树二分,找到某个前缀的 (0) 的数量正好是之前 (1) 的个数的位置,然后区间赋值成 (1) 即可

    对于 (2) 操作,显然的区间询问,注意两边的处理即可

    [代码]

    #include<cstdio>
    #include<iostream>
    #ifdef ONLINE_JUDGE
    char ss[1<<17],*A=ss,*B=ss;
    inline char gc(){if(A==B){B=(A=ss)+fread(ss,1,1<<17,stdin);if(A==B)return EOF;}return*A++;}
    template<class T>inline void read(T&x){
        static char c;static int y;
        for(c=gc(),x=0,y=1;c<48||57<c;c=gc())if(c=='-')y=-1;
        for(;48<=c&&c<=57;c=gc())x=((x+(x<<2))<<1)+(c^'0');
        x*=y;
    }
    #else
    void read(int &x){scanf("%d",&x);}
    #endif      //快读
    using namespace std;
    int ad[800001],sum[800001],n,t;
    inline void write(int x){if(x>9) write(x/10);putchar(x%10^48);}
    inline void pushup(int rt){
        sum[rt]=sum[rt<<1]+sum[rt<<1|1];
    }
    void build(int rt,int l,int r){     //菜鸡专属建树
        if (l==r){
            sum[rt]=1;
            return;
        }
        int m=(l+r)>>1;
        build(rt<<1,l,m);
        build(rt<<1|1,m+1,r);
        pushup(rt);
    }
    inline void pushdown(int rt,int l,int r){
        if (ad[rt]){
            int m=(l+r)>>1;
            ad[rt]--;
            sum[rt<<1]=ad[rt]*(m-l+1);
            sum[rt<<1|1]=ad[rt]*(r-m);
            ad[rt<<1]=ad[rt]+1;
            ad[rt<<1|1]=ad[rt]+1;
            ad[rt]=0;
        }
    }
    void update(int rt,int l,int r,int x,int y,int k){  //区间都附成k
        if (l>y||x>r) return;
        if (x<=l&&r<=y){
            ad[rt]=k+1;     //由于有0,k+1方便一些
            sum[rt]=k*(r-l+1);
            return;
        }
        pushdown(rt,l,r);
        int m=(l+r)>>1;
        if (m>=x) update(rt<<1,l,m,x,y,k);
        if (m<y) update(rt<<1|1,m+1,r,x,y,k);
        pushup(rt);
    }
    int query(int rt,int l,int r,int x,int y){      //查询区间和
        if (l>y||x>r) return 0;
        if (x<=l&&r<=y) return sum[rt];
        pushdown(rt,l,r);
        int m=(l+r)>>1,ret=0;
        if (m>=x) ret+=query(rt<<1,l,m,x,y);
        if (m<y) ret+=query(rt<<1|1,m+1,r,x,y);
        return ret;
    }
    inline int ef(int x,int y,int k){   //二分查找x到y之间连续最长的k序列
        int l=0,r=y-x,mid;
        if (x>y) return -1;
        while (l<=r){
            mid=(l+r)>>1;
            if (query(1,1,n,x,x+mid)==k*(mid+1)) l=mid+1;
            else r=mid-1;
        }
        return l;
    }
    int main(){
        int x,y,b,c,d;
        read(n); read(t);
        build(1,1,n);
        while (t--){
            read(b),read(x),read(y);
            if (b==0){
                update(1,1,n,x,y,0);
            }
            if (b==1){
                read(c),read(d);
                int num=query(1,1,n,x,y),p=0;
                update(1,1,n,x,y,0);
                if (num>=(d-c+1)-query(1,1,n,c,d)){ 
                    update(1,1,n,c,d,1); continue;
                }
                if (num==0) continue;//以上两个特判为菜鸡T了之后无助的挣扎
                while (1){
                    if (query(1,1,n,c,c)==1){   //开头为一
                        p=ef(c,d,1); c+=p; 
                    }
                    p=ef(c,d,0);
                    if (p==-1) break;
                    if (p>num){
                        update(1,1,n,c,c+num-1,1);
                        break;
                    }
                    else{
                        update(1,1,n,c,c+p-1,1);
                        num-=p; c+=p;
                    }
                }
            }
            if (b==2){
                int ans=0,p=0;
                while (1){
                    if (query(1,1,n,x,x)==1){
                        p=ef(x,y,1); x+=p;
                    }
                    p=ef(x,y,0);
                    if (p==-1) break;
                    ans=max(ans,p);
                    x+=p; if (x>y) break;   //忘写这个85分死循环
                }
                write(ans); puts("");
            }
        }
        return 0;
    }
    
  • 相关阅读:
    结构体
    Springmvc中异常处理
    SpringMVC的Controller方法返回值的3种类型
    SpringMVC的参数绑定
    @RequestParam用法与@PathVariable用法的区别
    springMVC架构(三大组件)
    springMVC入门程序开发步骤
    @RequestMapping的三个用法
    web.xml标签
    小笔记2(Servlet)
  • 原文地址:https://www.cnblogs.com/wawawa8/p/11113578.html
Copyright © 2020-2023  润新知