hdu 5828 Rikka with Sequence 【线段树+优化】

本文针对HDU OJ 5828题提出了一种基于线段树的数据结构解决方案,通过对区间进行加法、开方操作及求和查询,特别关注于如何优化处理大量操作时的效率问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

链接:http://acm.hdu.edu.cn/showproblem.php?pid=5828

题意:给你n个数,q个操作,操作k,l,r,k=1时 区间[l,r]每个数加x,k=2时,区间[l,r]每个数开平方,k=3时,求区间[l,r]的和。

分析:我们知道一个数多次开平方会变成1,但是这里的1操作会使这个数的值增大,所以直接判断一个区间是否为1肯定超时。

官方题解加了个优化,就是判断一个区间内是否为一个值,因为有些区间在操作1和2下会变成一个值。

但是有一组数据把标程hack了:10万个2,3,2,3,2,3.......,10万个操作 加6,开根。

这样每个数相等的区间大小就为1了,标程T了。

我们来考虑这种数据,如果一个区间的极差>1,那么经过多次1,2操作后,最终这个区间的极差要么是0,要么是1,那么我们只要维护极差<=1的区间就好了。

后来也T了很久。。。要用读入优化和输入加到build里,G++提交。

代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<string>
#include<vector>
#include<queue>
#include<cmath>
#include<stack>
#include<set>
#include<map>
#define INF 0x3f3f3f3f
#define Mn 100010
#define Mm 2000005
#define mod 1000000007
#define CLR(a,b) memset((a),(b),sizeof((a)))
#define CLRS(a,b,Size) memset((a),(b),sizeof((a[0]))*(Size+1))
#define CPY(a,b) memcpy ((a), (b), sizeof((a)))
#pragma comment(linker, "/STACK:102400000,102400000")
#define ul u<<1
#define ur (u<<1)|1
using namespace std;
typedef long long ll;
int read() {
    char c=getchar();
    int re=0,f=1;
    while(c<'0'||c>'9') {if(c=='-') f=-1;c=getchar();}
    while(c>='0'&&c<='9') {re=re*10+c-'0';c=getchar();}
    return re*f;
}
int a[Mn];
ll sum[Mn*4];
ll maxx[Mn*4],minn[Mn*4];
ll maxNum[Mn*4],minNum[Mn*4];
ll all[Mn*4];
ll lazy[Mn*4];
void pushUp(int u) {
    sum[u]=sum[ul]+sum[ur];
    maxx[u]=max(maxx[ul],maxx[ur]);
    minn[u]=min(minn[ul],minn[ur]);
    maxNum[u]=minNum[u]=0;
    if(maxx[u]==maxx[ul]) maxNum[u]+=maxNum[ul];
    if(maxx[u]==maxx[ur]) maxNum[u]+=maxNum[ur];
    if(minn[u]==minn[ul]) minNum[u]+=minNum[ul];
    if(minn[u]==minn[ur]) minNum[u]+=minNum[ur];
}
void pushDown(int u,int l,int r) {
    if(all[u]) {
        int mid=(l+r)>>1;
        all[ul]=all[ur]=all[u];
        sum[ul]=all[u]*(mid-l+1);
        sum[ur]=all[u]*(r-mid);
        maxx[ul]=maxx[ur]=minn[ul]=minn[ur]=all[u];
        maxNum[ul]=minNum[ul]=mid-l+1;
        maxNum[ur]=minNum[ur]=r-mid;
        lazy[ul]=lazy[ur]=0;
        all[u]=0;
    }
    if(lazy[u]) {
        int mid=(l+r)>>1;
        lazy[ul]+=lazy[u];lazy[ur]+=lazy[u];
        sum[ul]+=lazy[u]*(mid-l+1);
        sum[ur]+=lazy[u]*(r-mid);
        maxx[ul]+=lazy[u];minn[ul]+=lazy[u];
        maxx[ur]+=lazy[u];minn[ur]+=lazy[u];
        lazy[u]=0;
    }
}
void build(int l,int r,int u) {
    all[u]=lazy[u]=maxx[u]=minn[u]=sum[u]=0;
    if(l==r) {
        maxx[u]=minn[u]=sum[u]=read();
        maxNum[u]=minNum[u]=1;
        return ;
    }
    int mid=(l+r)>>1;
    build(l,mid,ul);
    build(mid+1,r,ur);
    pushUp(u);
}
int s,t;
void add(int l,int r,int u,int x) {
    if(s<=l&&t>=r) {
        sum[u]+=(ll)x*(r-l+1);
        minn[u]+=x;
        maxx[u]+=x;
        lazy[u]+=x;
        return ;
    }
    pushDown(u,l,r);
    int mid=(l+r)>>1;
    if(s<=mid) add(l,mid,ul,x);
    if(t>mid) add(mid+1,r,ur,x);
    pushUp(u);
}
void Sqrt(int l,int r,int u) {
    if(s<=l&&t>=r&&(maxx[u]-minn[u]<=1)) {
        if(maxx[u]==1) return ;
        int x=maxx[u];
        if(maxx[u]==minn[u]) {
            minn[u]=maxx[u]=floor(sqrt(x));
            lazy[u]+=maxx[u]-x;
            sum[u]=maxx[u]*(r-l+1);
            return ;
        } else if(maxx[u]-minn[u]==1){
            maxx[u]=floor(sqrt(maxx[u]));
            minn[u]=floor(sqrt(minn[u]));
            if(maxx[u]==minn[u]) {
                maxNum[u]=minNum[u]=r-l+1;
                lazy[u]=0;
                all[u]=maxx[u];
                sum[u]=maxx[u]*maxNum[u];
            } else if(maxx[u]-minn[u]==1) {
                lazy[u]+=maxx[u]-x;
                sum[u]=maxx[u]*maxNum[u]+minn[u]*minNum[u];
            }
            return ;
        }
        return ;
    }
    pushDown(u,l,r);
    int mid=(l+r)>>1;
    if(s<=mid) Sqrt(l,mid,ul);
    if(t>mid) Sqrt(mid+1,r,ur);
    pushUp(u);
}
ll query(int l,int r,int u) {
    if(s<=l&&t>=r) {
        return sum[u];
    }
    pushDown(u,l,r);
    int mid=(l+r)>>1;
    ll re=0;
    if(s<=mid) re+=query(l,mid,ul);
    if(t>mid) re+=query(mid+1,r,ur);
    return re;
}
int main() {
    int T=read(),k;
    while(T--) {
        int n=read(),m=read();
        build(1,n,1);
        while(m--) {
            k=read(),s=read(),t=read();
            if(k==1) {
                int x=read();
                add(1,n,1,x);
            } else if(k==2){
                Sqrt(1,n,1);
            } else {
                printf("%I64d\n",query(1,n,1));
            }
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值