UOJ - #228. 基础数据结构练习题

题意:

  一个区间支持三种操作,区间加,区间开根号和区间求和。

题解:

  线段树的做法。对于区间开根号操作,如果要开根号的区间最大值和最小值相等的话相当于区间减操作。当最大值和最小值相差1时,如果最大值是平方数那么也相当于区间减操作,否则就是区间覆盖。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#define lson (id<<1)
#define rson ((id<<1)|1)
#define mid ((l+r)>>1)
using namespace std;
typedef long long ll;
const int N = 1e5+10;
int n, m;
int t, l, r;
ll x;
ll lazy[N*5], maxx[N*5], minn[N*5], sum[N*5];
void push_up(int id) {
    maxx[id] = max(maxx[lson], maxx[rson]);
    minn[id] = min(minn[lson], minn[rson]);
    sum[id] = sum[lson]+sum[rson];
}
void build(int id, int l, int r) {
    lazy[id] = 0;
    if(l==r) {
        scanf("%lld", &sum[id]);
        maxx[id] = minn[id] = sum[id];
        return ;
    }
    build(lson, l, mid);
    build(rson, mid+1, r);
    push_up(id);
    return ;
}
void push_down(int id, int l, int r) {
    if(lazy[id]) {
        lazy[lson] += lazy[id];
        lazy[rson] += lazy[id];
        sum[lson] += 1ll*(mid-l+1)*lazy[id];
        sum[rson] += 1ll*(r-mid)*lazy[id];
        maxx[lson] += lazy[id];
        maxx[rson] += lazy[id];
        minn[lson] += lazy[id];
        minn[rson] += lazy[id];
        lazy[id] = 0;
    }
}
void ins(int id, int l, int r, int ql, int qr, ll x) {
    if(ql<=l&&r<=qr) {
        sum[id] += 1ll*(r-l+1)*x;
        lazy[id] += x;
        maxx[id] += x;
        minn[id] += x;
        return ;
    }
    push_down(id, l, r);
    if(ql<=mid) ins(lson, l, mid, ql, qr, x);
    if(qr>mid) ins(rson, mid+1, r, ql, qr, x);
    push_up(id);
}
void update(int id, int l, int r, int ql, int qr) {
    if(ql<=l&&r<=qr&&maxx[id]-minn[id]<=1) {
        ll k = (ll)sqrt(maxx[id]);
        if(maxx[id]-minn[id]==0||k*k==maxx[id]) {
            ins(id, l, r, l, r, k-maxx[id]);
            return ;
        }
    }
    push_down(id, l, r);
    if(ql<=mid) update(lson, l, mid, ql, qr);
    if(qr>mid) update(rson, mid+1, r, ql, qr);
    push_up(id);
}
ll query(int id, int l, int r, int ql, int qr) {
    if(ql<=l&&r<=qr) return sum[id];
    push_down(id, l, r);
    ll res = 0;
    if(ql<=mid) res += query(lson, l, mid, ql, qr);
    if(qr>mid) res += query(rson, mid+1, r, ql, qr);
    push_up(id);
    return res;
}
int main() {
    scanf("%d%d", &n, &m);
    build(1, 1, n);
    while(m--) {
        scanf("%d%d%d", &t, &l, &r);
        if(t==1) {
            scanf("%lld", &x);
            ins(1, 1, n, l, r, x);
        }
        if(t==2) update(1, 1, n, l, r);
        if(t==3) printf("%lld\n", query(1, 1, n, l, r));
    }
}

原文地址:https://www.cnblogs.com/Pneuis/p/9026039.html

时间: 2024-10-18 12:32:33

UOJ - #228. 基础数据结构练习题的相关文章

【UOJ#228】基础数据结构练习题 线段树

#228. 基础数据结构练习题 题目链接:http://uoj.ac/problem/228 Solution 这题由于有区间+操作,所以和花神还是不一样的. 花神那道题,我们可以考虑每个数最多开根几次就会成1,而这个必须利用开根的性质 我们维护区间最大.最小.和.区间加操作可以直接做. 区间开方操作需要特殊考虑. 首先对于一个区间,如果这个区间的所有数取$x=\left \lfloor \sqrt{x} \right \rfloor$值一样,那么就可以直接区间覆盖. 分析上述过程,一个区间可以

UOJ228 基础数据结构练习题

本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/转载请注明出处,侵权必究,保留最终解释权! 题目链接:http://uoj.ac/problem/228 本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 正解:线段树 解题报告: 这道题是一道线段树的神题,需要我们支持区间开方.区间加法和区间求和操作. 关键是对于开方操作的处理,考虑如果一个区间最大值等于最小值(即全都相等),那么就可以直接开方,

【uoj228】 基础数据结构练习题

http://uoj.ac/problem/228 (题目链接) 题意 给出一个序列,维护区间加法,区间开根,区间求和 Solution 线段树.考虑区间开根怎么做.当区间的最大值与最小值相等时,我们直接对整个区间开根.最坏情况下,一次开根的复杂度最坏是${O(nlogn)}$的,然而每次开根可以迅速拉近两个数之间的大小差距,最坏复杂度的开根不会超过${5}$次. 但是考虑这样一种情况:${\sqrt{x+1}=\sqrt{x}+1}$,如果序列长成这样:${65535,65536,65535,

[UOJ228] 基础数据结构练习题 - 线段树

考虑到一个数开根号 \(loglog\) 次后就会变成1,设某个Node的势能为 \(loglog(maxv-minv)\) ,那么一次根号操作会使得势能下降 \(1\) ,一次加操作最多增加 \(logloga\) 的势能. #include <bits/stdc++.h> using namespace std; typedef long long ll; const int N = 400005; ll sum[N],mx[N],mn[N],tag[N],src[N]; void add

6、50道JAVA基础编程练习题跟答案

1 50道JAVA基础编程练习题 2 [程序1] 3 题目:古典问题:有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,问每个月的兔子总数为多少? 4 程序分析: 兔子的规律为数列1,1,2,3,5,8,13,21.... 5 public class Prog1{ 6 public static void main(String[] args){ 7 int n = 10; 8 System.out.println("第"+n+

Linux运维常见基础面试练习题(1)

Linux运维常见基础面试练习题(1) 1 创建目录/data/oldboy,并且在该目录下创建文件oldboy.txt,然后在文件oldbot.txt里写入内容"inet addr:10.0.0.8 Bcast:10.0.0.225 Mask:255.255.255.0"不包含引号 方法一 [[email protected] /]# mkdir /data/oldboy -p [[email protected] /]# cd /data/oldboy/ [[email prote

Java基础——面向对象练习题

1.建立一个图形接口,声明一个面积函数.计算圆形和矩形的面积.注:体现面向对象的特征,对象值进行判断,用异常处理.不合法的数值需要出现"这个数值是非法的提示",不再进行运算. 2.在一个类中编写一个方法,这个方法搜索一个字符数组是否存在某个字符.如果存在则返回这个字符在数组中第一次出现的位置,否则返回-1.需要搜索的字符数组和字符都一参数的形式传递给该方法.如果传入的数组为NULL,则应该抛出IllegalArgumentException异常. 3.补充compare函数代码. 4.

排序与基础数据结构

6大排序与6大基础数据结构 本文从冒泡排序撩起,对选择.插入.希尔.归并.快排6种经典的数组排序进行了深入分析,并详解其间的关联,让你深刻理解其中的关键点:同时对经典的数据结构Vector.Stack.Queue.树.Map.Set做了归纳总结,对其底层的实现做了解析,分享给大家,作为每一个中高级程序员应该懂得的算法与排序,祝大家早上走上自己的"成金之路". 目录: 1.排序算法 2.数据结构 3.资料参考 1.排序算法: a.起源: 计算机从诞生起,就在模拟人这种智能生物的行为,而排

java 基础数据结构

数据结构, 需要考虑两个方面: 1. 每个元素具体的存储方法 (java中是一个对象) 2. 元素之间的关系如何实现存储 (java中也是一个对象) 另外在java中, 已经可以把跟数据结构有关的一些方法写到一个类里了. 线性表 顺序表 c语言: 借助数组实现 #define INIT_SIZE 100; typedef struct { int elem[INIT_SIZE]; // 用来存储数组元素 int length; // 当前顺序表的长度 } SqList; // 元素之间的关系隐含