Rikka with Sequence---hdu5828(区间更新与查找 线段树)

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

给你n个数,m个操作,操作k,l,r,

k=1时 区间[l,r]每个数加x;

k=2时,区间[l,r]每个数开平方;

k=3时,求区间[l,r]的和。

开方的操作执行的次数,并不多到所以最后会出现很多相同的数,我们可以把相同的数统一减去一个数即可,但是数据中如果存在2 3 2 3 2 3 2 3,有10w次+6,然后开方,这样的话,时间复杂度也是很高的;所以我们可以看到,只要两个数相差一,开方后还相差一,那么我们可以减去一个数完成;

#include<iostream>
#include<algorithm>
#include<string.h>
#include<stdio.h>
#include<math.h>
using namespace std;
#define N 100005
#define met(a, b) memset(a, b, sizeof(a))
#define mod 1000000007
typedef long long LL;
#define Lson r<<1
#define Rson r<<1|1

struct Tree
{
    int L, R;
    LL lazy, Min, Max, sum;
    int mid() { return (L+R)/2; }
    int len() { return (R-L+1); }
}a[N<<2];

void BuildTree(int r, int L, int R)
{
    a[r].L = L; a[r].R = R; a[r].lazy = 0;

    if(a[r].L == a[r].R)
    {
        scanf("%I64d", &a[r].sum);
        a[r].Max = a[r].Min = a[r].sum;
        return ;
    }

    BuildTree(Lson, L, a[r].mid());
    BuildTree(Rson, a[r].mid()+1, R);

    a[r].sum = a[Lson].sum + a[Rson].sum;
    a[r].Max = max(a[Lson].Max, a[Rson].Max);
    a[r].Min = min(a[Lson].Min, a[Rson].Min);
}

void Down(int r)
{
    a[Lson].lazy += a[r].lazy; a[Rson].lazy += a[r].lazy;

    a[Lson].sum += a[Lson].len()*a[r].lazy;
    a[Rson].sum += a[Rson].len()*a[r].lazy;

    a[Lson].Max += a[r].lazy; a[Rson].Max += a[r].lazy;
    a[Lson].Min += a[r].lazy; a[Rson].Min += a[r].lazy;

    a[r].lazy = 0;
}

void Up(int r)
{
    a[r].sum = a[Lson].sum + a[Rson].sum;

    a[r].Max = max(a[Lson].Max, a[Rson].Max);
    a[r].Min = min(a[Lson].Min, a[Rson].Min);
}

void Update1(int r, int L, int R, LL num)
{
    a[r].sum += (R-L+1) * num;
    if(a[r].L == L && a[r].R == R)
    {
        a[r].Max += num;
        a[r].Min += num;
        a[r].lazy += num;
        return ;
    }

    Down(r);///往下传递Lazy;

    if(R <= a[r].mid())
        Update1(Lson, L, R, num);
    else if(L > a[r].mid())
        Update1(Rson, L, R, num);
    else
    {
        Update1(Lson, L, a[r].mid(), num);
        Update1(Rson, a[r].mid()+1, R, num);
    }

    Up(r);///往上传递Lazy;
}
void Update2(int r, int L, int R)
{
    if(a[r].L == L && a[r].R == R)
    {
        if(a[r].Min == a[r].Max)///当区间内所有的数都相等时,相当于区间内所有数都减去同一个数;
        {
            LL num = (LL)sqrt(a[r].Max) - a[r].Max;
            a[r].sum += a[r].len() * num;
            a[r].lazy += num;
            a[r].Max += num;
            a[r].Min += num;

            return;
        }
        else if(a[r].Min + 1 == a[r].Max)///当数之间相差<=1的时候并且开方之后还是相差1的话,那么他们可以通过加一个数得到;
        {
            LL num1 = (LL)sqrt(a[r].Max);
            LL num2 = (LL)sqrt(a[r].Min);
            if(num1 == num2+1)
            {
                LL num = num1 - a[r].Max;
                a[r].sum += a[r].len() * num;
                a[r].lazy += num;
                a[r].Max += num;
                a[r].Min += num;
                return;
            }
        }
    }

    Down(r);

    if(R <= a[r].mid())
        Update2(Lson, L, R);
    else if(L > a[r].mid())
        Update2(Rson, L, R);
    else
    {
        Update2(Lson, L, a[r].mid());
        Update2(Rson, a[r].mid()+1, R);
    }

    Up(r);
}
LL Query(int r, int L, int R)
{
    if(L == a[r].L && R == a[r].R)
    {
        return a[r].sum;
    }
    Down(r);
    if(R <= a[r].mid())
        return Query(Lson, L, R);
    else if(L > a[r].mid())
        return Query(Rson, L, R);
    else
    {
        LL ans1 = Query(Lson, L, a[r].mid());
        LL ans2 = Query(Rson, a[r].mid()+1, R);
        return ans1 + ans2;
    }
}

int main()
{
    int T;
    scanf("%d", &T);
    while(T--)
    {
        int n, m, op, L, R; LL num;

        scanf("%d %d", &n, &m);

        BuildTree(1, 1, n);

        while(m--)
        {
            scanf("%d", &op);
            if(op == 1)
            {
                scanf("%d %d %I64d", &L, &R, &num);
                Update1(1, L, R, num);
            }
            else if(op == 2)
            {
                scanf("%d %d", &L, &R);
                Update2(1, L, R);
            }
            else
            {
                scanf("%d %d", &L, &R);
                LL ans = Query(1, L, R);
                printf("%I64d
", ans);
            }
        }
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/zhengguiping--9876/p/5776361.html