zoukankan      html  css  js  c++  java
  • F. Raging Thunder 线段树 + 区间合并

    F. Raging Thunder

    先感叹一句,这个题目真变态,我写了五六个小时。。。。。而且还是在知道怎么写的情况下。。。

    题目大意:

    给你一个字符串,这个字符串只包含 (>)(<) ,其中 (>) 表示该位置的球会向右滚一格, (<) 表示该位置的球会向左滚一格,如果最左边是 (<) 则表示球会落到位置为0的这个洞里,如果最右边是 (>) 则表示球会落到位置为 (n+1) 的这个洞里。一共有 (m) 次询问,每次询问给你一个区间 ([l,r]) ,表示这个区间的所有的字符会反向,即 (>) 变成 (<)(<) 变成 (>) ,而且这个区间每个位置会落下一颗球,找出一个洞中最大的球的数量,提示:每一次询问之后,字符的改变会保留。

    题解:

    • 先把这个字符串转化成01字符串,(>) 表示1,(<) 表示0,这个题目就转化成求最长的1...0...字符串
    • 然后你会发现我们要求的字符串就类似于 00111000111,起始是01,结束也是01,结果转化为求间隔最远的01。
    • 第三步就是把01,00,10,11进行转化以便于求间隔最远的01
    • 把00转化为2,01转化为0,10转化为3,11转化为1
    • 最后需要维护的有最长的0的间隔,最长的3的间隔,最左边的0、3,最右边的0、3
    • 对于一个区间进行更新,容易得到就是把0换成了3,1换成了2
      • 例如:000111 那么转化后 22011,对这整个区间进行更新则变成111000,转化后11322
    • 但是要注意的是更新一个区间,其左右端点需要单独更新,这个可以自己想清楚

    这个是我写之前就知道了的,之后写的过程中写出来很多的bug

    • 求解需要一个区间合并
    • 区间合并的时候要注意限制在求的范围内
    • 还有一些写在代码里面了

    这个题目的转化挺难想的,也很考验码力,和区间合并的线段树很像

    #include <bits/stdc++.h>
    #define inf 0x3f3f3f3f
    #define inf64 0x3f3f3f3f3f3f3f3f
    #define debug(x) printf("debug:%s=%d
    ",#x,x);
    //#define debug(x) cout << #x << ": " << x << endl
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    const int maxn =5e5+10;
    int lc0[maxn*4],lc3[maxn*4],rc0[maxn*4],rc3[maxn*4];
    int len0[maxn*4],len3[maxn*4],a[maxn],lazy[maxn*4];
    char s[maxn];
    
    void push_up(int id){
        lc0[id]=min(lc0[id<<1],lc0[id<<1|1]);
        lc3[id]=min(lc3[id<<1],lc3[id<<1|1]);
        rc0[id]=max(rc0[id<<1],rc0[id<<1|1]);
        rc3[id]=max(rc3[id<<1],rc3[id<<1|1]);
    
        len0[id]=max(len0[id<<1],len0[id<<1|1]);
        len3[id]=max(len3[id<<1],len3[id<<1|1]);
        if(lc0[id<<1|1]!=inf&&rc0[id<<1]!=0) len0[id]=max(len0[id],lc0[id<<1|1]-rc0[id<<1]);
        if(lc3[id<<1|1]!=inf&&rc3[id<<1]!=0) len3[id]=max(len3[id],lc3[id<<1|1]-rc3[id<<1]);
    //    printf("lec0[%d]=%d
    ",id,len0[id]);
    //    printf("l  len=%d    r  len=%d
    ",len0[id<<1],len0[id<<1|1]);
    //    printf("lc0[%d]=%d  rc[%d]=%d
    ",id<<1|1,lc0[id<<1|1],id<<1,rc0[id<<1]);
    }
    
    void build(int id,int l,int r){
        if(l==r){
            if(a[l]==0) lc0[id]=l,rc0[id]=l;
            if(a[l]==3) lc3[id]=l,rc3[id]=l;
            return ;
        }
        int mid=(l+r)>>1;
        build(id<<1,l,mid);
        build(id<<1|1,mid+1,r);
        push_up(id);
    }
    
    void change(int id,int l,int r){
        //如果是叶子节点,则直接更新即可,不需要进行swap
        if(l==r) {
            a[l]=3-a[l];
            //无论这个位置是什么都要注意状态的更新,是0,则也要更新3的状态
            if(a[l]==0) lc0[id]=l,rc0[id]=l,lc3[id]=inf,rc3[id]=0;
            else if(a[l]==3) lc3[id]=l,rc3[id]=l,lc0[id]=inf,rc0[id]=0;
            else lc0[id]=inf,lc3[id]=inf,rc0[id]=0,rc3[id]=0;
    //        printf("a[%d]=%d id=%d l=%d r=%d
    ",l,a[l],id,lc0[id],rc0[id]);
        }
        else{
            lazy[id]^=1;
            swap(len0[id],len3[id]);
            swap(lc0[id],lc3[id]);
            swap(rc0[id],rc3[id]);
        }
    }
    
    void push_down(int id,int l,int r){
    //    printf("id=%d l=%d r=%d lazy=%d
    ",id,l,r,lazy[id]);
        if(lazy[id]==0) return ;
        int mid=(l+r)>>1;
        change(id<<1,l,mid);
        change(id<<1|1,mid+1,r);
        lazy[id]=0;
    }
    
    void update(int id,int l,int r,int x,int y){
    //	printf("update id=%d l=%d r=%d x=%d y=%d
    ",id,l,r,x,y);
        if(x>r||y<l) return ;
        if(x<=l&&y>=r){
            change(id,l,r);
    //        printf("updatein  lc0[%d]=%d rc0[%d]=%d a[%d]=%d
    ",id,lc0[id],id,rc0[id],l,a[l]);
            return ;
        }
        push_down(id,l,r);
        int mid=(l+r)>>1;
        if(x<=mid) update(id<<1,l,mid,x,y);
        if(y>mid) update(id<<1|1,mid+1,r,x,y);
        push_up(id);
    }
    
    int query(int id,int l,int r,int x,int y){
        if(x<=l&&y>=r) return len0[id];
    //    printf("ans1  id=%d l=%d r=%d x=%d y=%d
    ",id,l,r,x,y);
        int mid=(l+r)>>1,ans=0;
        push_down(id,l,r);
        //区间合并
        if(y<=mid) return query(id<<1,l,mid,x,y);
        else if(x>mid) return query(id<<1|1,mid+1,r,x,y);
        else{
            int ans1 =query(id<<1,l,mid,x,y);
            int ans2 =query(id<<1|1,mid+1,r,x,y);
            int ans3 =0;
            if(lc0[id<<1|1]!=inf&&rc0[id<<1]!=0) ans3 = min(y,lc0[id<<1|1])-max(rc0[id<<1],x);
            //在min(y,lc0[id<<1|1]) max(x,rc0[id<<1]) 这个是因为求的范围是 x y,但是这个位置可能大于y或者小于x,所以这里要做一个限制
    //    	printf("id=%d ans1=%d ans2=%d ans3=%d
    ",id,ans1,ans2,ans3);
            return max(ans1,max(ans2,ans3));
        }
    }
    
    int querylc(int id,int l,int r,int x,int y){
        if(x<=l&&y>=r) return lc0[id];
        int mid=(l+r)>>1,ans=inf;
    //    printf("ans2 id=%d
    ",id);
        push_down(id,l,r);
        if(x<=mid) ans=min(ans,querylc(id<<1,l,mid,x,y));
        if(y>mid) ans=min(ans,querylc(id<<1|1,mid+1,r,x,y));
        return ans;
    }
    int queryrc(int id,int l,int r,int x,int y){
        if(x<=l&&y>=r) return rc0[id];
        int mid=(l+r)>>1,ans=0;
    //    printf("ans3 id=%d
    ",id);
        push_down(id,l,r);
        if(x<=mid) ans=max(ans,queryrc(id<<1,l,mid,x,y));
        if(y>mid) ans=max(ans,queryrc(id<<1|1,mid+1,r,x,y));
        return ans;
    }
    
    void modify(int id,int l,int r,int pos,int f){
        if(l==r){
    //        printf("before f=%d a[%d]=%d
    ",f,l,a[l]);
            //无论这个位置是什么都要注意状态的更新,是0,则也要更新3的状态
            if(f==1){
                if(a[l]==3) a[l]=1,lc3[id]=inf,rc3[id]=0;
                else if(a[l]==1) a[l]=3,lc3[id]=l,rc3[id]=l;
                else if(a[l]==0) a[l]=2,lc0[id]=inf,rc0[id]=0;
                else if(a[l]==2) a[l]=0,lc0[id]=l,rc0[id]=r;
            }
            else{
                if(a[l]==3) a[l]=2,lc3[id]=inf,rc3[id]=0;
                else if(a[l]==2) a[l]=3,lc3[id]=l,rc3[id]=l;
                else if(a[l]==0) a[l]=1,lc0[id]=inf,rc0[id]=0;
                else if(a[l]==1) a[l]=0,lc0[id]=l,rc0[id]=r;
            }
    //        printf("f=%d a[%d]=%d
    ",f,l,a[l]);
            return ;
        }
    //    printf("ss id=%d l=%d r=%d
    ",id,l,r);
        int mid=(l+r)>>1;
        push_down(id,l,r);
        if(pos<=mid) modify(id<<1,l,mid,pos,f);
        if(pos>mid) modify(id<<1|1,mid+1,r,pos,f);
        push_up(id);
    }
    
    void push_alldown(int id,int l,int r){
        if(l==r) return ;
    //    printf("id=%d  ddd
    ",id);
        push_down(id,l,r);
        int mid=(l+r)>>1;
        push_alldown(id<<1,l,mid);
        push_alldown(id<<1|1,mid+1,r);
    }
    
    void print(int n){
        for(int i=1;i<=n;i++) printf("a[%d]=%d	",i,a[i]);
        printf("
    ");
    }
    
    int main(){
        int n,m;
        memset(lc0,inf,sizeof(lc0));
        memset(lc3,inf,sizeof(lc3));
        scanf("%d%d",&n,&m);
        scanf("%s",s+1);
        if(n==1){
            while(m--) printf("%d
    ",1);
            return 0;
        }
        for(int i=1;i<n;i++){
            if(s[i]=='>'&&s[i+1]=='<') a[i]=3;
            if(s[i]=='<'&&s[i+1]=='>') a[i]=0;
            if(s[i]=='>'&&s[i+1]=='>') a[i]=1;
            if(s[i]=='<'&&s[i+1]=='<') a[i]=2;
        }
        build(1,1,n-1);
    //    print(n-1);
        for(int i=1;i<=m;i++){
            int x,y;
            scanf("%d%d",&x,&y);
            update(1,1,n-1,x,y-1);
    
            if(x>1) modify(1,1,n-1,x-1,1);
            if(y<n) modify(1,1,n-1,y,2);
    //        printf("xxx
    ");
    //        push_alldown(1,1,n-1);
    //        print(n-1);
    
            if(x==y){
                printf("1
    ");
                continue;
            }
    
            int ans=query(1,1,n-1,x,y-1);
            int lc=querylc(1,1,n-1,x,y-1);
            int rc=queryrc(1,1,n-1,x,y-1);
    
    
    //        printf("
    
    ");
            if(rc==0) printf("%d
    ",y-x+1);
            else{
    //        	printf("lc=%d rc=%d ans=%d
    ",lc,rc,ans);
                ans=max(ans,max(y-rc,lc-x+1));
                printf("%d
    ",ans);
            }
        }
    }
    
    
  • 相关阅读:
    hdu 4370
    lightoj 1074
    poj 1026
    poj 3159
    poj3660 cow contest
    hdu 4069 垃圾数独
    操作系统概念题复习
    ARM指令
    C++ 抢占时优先级进程调度
    Docker 入门
  • 原文地址:https://www.cnblogs.com/EchoZQN/p/13281087.html
Copyright © 2011-2022 走看看