hdu4973 线段树

题意:给定的序列 有两个操作 1将其中一段加倍 2询问段中的最长相等数字是多少

解法:直接上线段树就可以了 但是-》边界问题比较麻烦 有两种做法 一种在更新的时候直接判定边界,另外一种则是选定完边界再进行更新,题解的说法里面是第二种啊,但是比赛的时候不敢敲,怕码力不够啊。有点后悔的


首先是麻烦的写法:

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
#define ls (rt<<1)
#define rs (rt<<1|1)
#define mid ((l+r)>>1)
#define ll __int64
#define maxn 55555
ll sum[maxn<<2],mul[maxn<<2],ma[maxn<<2];
void up(int rt,int l,int r){
    sum[rt]=sum[ls]+sum[rs];
    ma[rt]=max(ma[ls],ma[rs]);
}
void down(int rt,int l,int r){
    if(mul[rt]){
        sum[ls]<<=mul[rt];
        sum[rs]<<=mul[rt];
        ma[ls]<<=mul[rt];
        ma[rs]<<=mul[rt];
        mul[ls]+=mul[rt];
        mul[rs]+=mul[rt];
        mul[rt]=0;
    }
}
void build(int rt,int l,int r){
    mul[rt]=0;
    if(l==r){
        sum[rt]=ma[rt]=(ll)1;
        return ;
    }
    build(ls,l,mid);
    build(rs,mid+1,r);
    up(rt,l,r);
}
int queryl(int rt,int l,int r,ll w){
    if(l==r)return l;
    down(rt,l,r);
    
    if(sum[ls]>=w){
        return queryl(ls,l,mid,w);
    }else return queryl(rs,mid+1,r,w-sum[ls]);
}
void ins(int rt,int l,int r,int L,int R){
    if(L<=l&&r<=R){
        sum[rt]<<=1;
        ma[rt]<<=1;
        mul[rt]++;
        return ;
    }down(rt,l,r);
    if(L<=mid)ins(ls,l,mid,L,R);
    if(mid<R)ins(rs,mid+1,r,L,R);
    up(rt,l,r);
}
void ins_s(int rt,int l,int r,int L,int R,ll w){
    if(L<=l&&r<=R){
        sum[rt]+=w;
        ma[rt]+=w;
        return ;
    }down(rt,l,r);
    if(L<=mid)ins_s(ls,l,mid,L,R,w);
    if(mid<R)ins_s(rs,mid+1,r,L,R,w);
    up(rt,l,r);
}
ll querys(int rt,int l,int r,int L,int R){
    if(L<=l&&r<=R){
        return sum[rt];
    }down(rt,l,r);
    ll res=0;
    if(L<=mid)res+=querys(ls,l,mid,L,R);
    if(mid<R)res+=querys(rs,mid+1,r,L,R);
    return res;
}
ll query(int rt,int l,int r,int L,int R){
    if(L<=l&&r<=R)return ma[rt];
    down(rt,l,r);
    ll res=0;
    if(L<=mid)res=max(res,query(ls,l,mid,L,R));
    if(mid<R)res=max(res,query(rs,mid+1,r,L,R));
    return res;
}
int n,m;
char op[111];
int main(){
    int _;scanf("%d",&_);
    for(int z=1;z<=_;++z){
        scanf("%d%d",&n,&m);
        build(1,1,n);ll l,r;
        printf("Case #%d:\n",z);
        while(m--){
            scanf("%s%I64d%I64d",op,&l,&r);
            if(l>r)swap(l,r);
            int lf=queryl(1,1,n,l);
            int ri=queryl(1,1,n,r);
            ll lsum=querys(1,1,n,1,lf),rsum;
            if(ri>1)rsum=querys(1,1,n,1,ri-1);
            else rsum=0;
            //            printf("%d %d %lld %lld\n",lf,ri,lsum,rsum);
            if(*op=='D'){
                if(lf==ri){
                    ins_s(1,1,n,lf,lf,r-l+1);
                }else{
                    if(lf+1<=ri-1)ins(1,1,n,lf+1,ri-1);
                    ins_s(1,1,n,lf,lf,lsum-l+1);
                    ins_s(1,1,n,ri,ri,r-rsum);
                }
            }
            else{
                if(lf==ri){
                    printf("%I64d\n",r-l+1);
                }else{
                    ll maxx=0;
                    if(lf+1<=ri-1)maxx=max(maxx,query(1,1,n,lf+1,ri-1));
                    maxx=max(maxx,lsum-l+1);
                    maxx=max(maxx,r-rsum);
                    printf("%I64d\n",maxx);
                }
            }
        }
    }
    return 0;
}

其次是比较简洁的:

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
#define ls (rt<<1)
#define rs (rt<<1|1)
#define mid ((l+r)>>1)
#define ll __int64
#define maxn 55555
int scan()
{
    int res=0,ch;
    while(!((ch= getchar())>='0'&&ch<='9')){
        if(ch==EOF)return 1<<30;
    }
    res=ch-'0';
    while((ch=getchar())>='0'&&ch<='9')
        res=res*10+(ch-'0');
    return res;
}
ll sum[maxn<<2],mul[maxn<<2],ma[maxn<<2];
void up(int rt,int l,int r){
    sum[rt]=sum[ls]+sum[rs];
    ma[rt]=max(ma[ls],ma[rs]);
}
void down(int rt,int l,int r){
    if(mul[rt]){
        sum[ls]<<=mul[rt];
        sum[rs]<<=mul[rt];
        ma[ls]<<=mul[rt];
        ma[rs]<<=mul[rt];
        mul[ls]+=mul[rt];
        mul[rs]+=mul[rt];
        mul[rt]=0;
    }
}
void build(int rt,int l,int r){
    mul[rt]=0;
    if(l==r){
        sum[rt]=ma[rt]=(ll)1;
        return ;
    }
    build(ls,l,mid);
    build(rs,mid+1,r);
    up(rt,l,r);
}
void insr(int rt,int l,int r,ll L,ll R){
    if(l==r){
        ma[rt]=sum[rt]+=R-L+1;
        return ;
    }else if(R-L+1==sum[rt]){
        sum[rt]<<=1;ma[rt]<<=1;mul[rt]++;
        return ;
    }down(rt,l,r);
    if(sum[ls]>=R)insr(ls,l,mid,L,R);
    else if(sum[ls]<L)insr(rs,mid+1,r,L-sum[ls],R-sum[ls]);
    else{
        insr(rs,mid+1,r,1,R-sum[ls]);
        insr(ls,l,mid,L,sum[ls]);
    }
    up(rt,l,r);
}
ll queryr(int rt,int l,int r,ll L,ll R){
    if(l==r)return R-L+1 ;
    if(R-L+1==sum[rt])return ma[rt];
    down(rt,l,r);
    if(sum[ls]>=R)return queryr(ls,l,mid,L,R);
    if(sum[ls]<L)return queryr(rs,mid+1,r,L-sum[ls],R-sum[ls]);
    return max(queryr(ls,l,mid,L,sum[ls]),queryr(rs,mid+1,r,1,R-sum[ls]));
}
int n,m;
char op[111];
int main(){
    int _;scanf("%d",&_);
    for(int z=1;z<=_;++z){
        scanf("%d%d",&n,&m);
        
        build(1,1,n);ll l,r;
        printf("Case #%d:\n",z);
        while(m--){
            scanf("%s%I64d%I64d",op,&l,&r);
            if(*op=='D'){
                insr(1,1,n,l,r);
            }
            else{
                printf("%I64d\n",queryr(1,1,n,l,r));
            }
        }
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值