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


    get到了标记永久化

    sylvia 是一个热爱学习的女孩子,今天她想要学习数据结构技巧。

    在看了一些博客学了一些姿势后,她想要找一些数据结构题来练练手。于是她的好朋友九条可怜酱给她出了一道题。

    给出一个长度为 nn 的数列 AA,接下来有 mm 次操作,操作有三种:

    1. 对于所有的 i[l,r]i∈[l,r],将 AiAi 变成 Ai+xAi+x。
    2. 对于所有的 i[l,r]i∈[l,r],将 AiAi 变成 Ai−−√⌊Ai⌋。
    3. 对于所有的 i[l,r]i∈[l,r],询问 AiAi 的和。

    作为一个不怎么熟练的初学者,sylvia 想了好久都没做出来。而可怜酱又外出旅游去了,一时间联系不上。于是她决定向你寻求帮助:你能帮她解决这个问题吗。

    输入格式

    第一行两个数:n,mn,m。

    接下来一行 nn 个数 AiAi。

    接下来 mm 行中,第 ii 行第一个数 titi 表示操作类型:

    若 ti=1ti=1,则接下来三个整数 li,ri,xili,ri,xi,表示操作一。

    若 ti=2ti=2,则接下来三个整数 li,rili,ri,表示操作二。

    若 ti=3ti=3,则接下来三个整数 li,rili,ri,表示操作三。

    输出格式

    对于每个询问操作,输出一行表示答案。

    数据范围

    对于所有数据,保证有 1lirin,1Ai,xi1051≤li≤ri≤n,1≤Ai,xi≤105

    时间限制:1s1s

    空间限制:256MB


    题目分析

    考虑只有区间开方和区间求和的操作,那么注意到开根号几次后数就变为1了,于是可以暴力做下去(或者分块弄一弄?)。

    然而问题麻烦在于还结合了区间加的操作,于是会出现形如898989->232323->898989的极端数据卡掉暴力区间下爬的方法。

    注意到若区间最大值等于区间最小值时就等于区间赋值(或者区间减)操作,并且复杂度最坏的情况只会在最大值与最小值相差1的时候发生。

    那么相当于只要在区间开方时特判一下就好了。

    (从别人博客get到了永久化标记的写法(据说常数挺小?))

    复杂度证明:UOJ 228 基础数据结构练习题

     1 #include<bits/stdc++.h>
     2 typedef long long ll;
     3 const int maxn = 100035;
     4 
     5 struct node
     6 {
     7     ll sum,mx,mn,tag;
     8 }f[maxn<<2];
     9 int n,m;
    10 
    11 int read()
    12 {
    13     char ch = getchar();
    14     int num = 0;
    15     bool fl = 0;
    16     for (; !isdigit(ch); ch = getchar())
    17         if (ch=='-') fl = 1;
    18     for (; isdigit(ch); ch = getchar())
    19         num = (num<<1)+(num<<3)+ch-48;
    20     if (fl) num = -num;
    21     return num;
    22 }
    23 void pushup(int rt, int lens)
    24 {
    25     f[rt].sum = f[rt<<1].sum+f[rt<<1|1].sum+1ll*f[rt].tag*lens;
    26     f[rt].mx = std::max(f[rt<<1].mx, f[rt<<1|1].mx)+f[rt].tag;
    27     f[rt].mn = std::min(f[rt<<1].mn, f[rt<<1|1].mn)+f[rt].tag;
    28 }
    29 void tagAdd(int rt, int lens, ll c)
    30 {
    31     f[rt].tag += c, f[rt].mn += c, f[rt].mx += c, f[rt].sum += 1ll*lens*c;
    32 }
    33 void build(int rt, int l, int r)
    34 {
    35     if (l==r){
    36         f[rt].sum = f[rt].mx = f[rt].mn = read();
    37         return;
    38     }
    39     int mid = (l+r)>>1;
    40     build(rt<<1, l, mid), build(rt<<1|1, mid+1, r);
    41     pushup(rt, r-l+1);
    42 }
    43 void updateAdd(int rt, int L, int R, int l, int r, ll c)
    44 {
    45     if (L <= l&&r <= R){
    46         tagAdd(rt, r-l+1, c);
    47         return;
    48     }
    49     int mid = (l+r)>>1;
    50     if (L <= mid) updateAdd(rt<<1, L, R, l, mid, c);
    51     if (R > mid) updateAdd(rt<<1|1, L, R, mid+1, r, c);
    52     pushup(rt, r-l+1);
    53 }
    54 void updateSqrt(int rt, int L, int R, int l, int r, ll tag)
    55 {
    56     if (L <= l&&r <= R){
    57         ll s = sqrt(f[rt].mn+tag)+1, t = sqrt(f[rt].mx+tag);
    58         if ((f[rt].mx==f[rt].mn)||(f[rt].mx==f[rt].mn+1&&s==t)){
    59             tagAdd(rt, r-l+1, s-1-f[rt].mn-tag);    //这一步是用来保证复杂度的
    60             return;
    61         }
    62     }
    63     int mid = (l+r)>>1;
    64     if (L <= mid) updateSqrt(rt<<1, L, R, l, mid, tag+f[rt].tag);
    65     if (R > mid) updateSqrt(rt<<1|1, L, R, mid+1, r, tag+f[rt].tag);
    66     pushup(rt, r-l+1);
    67 }
    68 ll query(int rt, int L, int R, int l, int r, ll tag)
    69 {
    70     if (L <= l&&r <= R)
    71         return f[rt].sum+1ll*tag*(r-l+1);
    72     int mid = (l+r)>>1;
    73     ll ret = 0;
    74     if (L <= mid) ret = query(rt<<1, L, R, l, mid, tag+f[rt].tag);
    75     if (R > mid) ret += query(rt<<1|1, L, R, mid+1, r, tag+f[rt].tag);
    76     return ret;
    77 }
    78 int main()
    79 {
    80     n = read(), m = read();
    81     build(1, 1, n);
    82     while (m--)
    83     {
    84         int opt = read();
    85         if (opt==1){
    86             int l = read(), r = read(), c = read();
    87             updateAdd(1, l, r, 1, n, c);
    88         }
    89         if (opt==2){
    90             int l = read(), r = read();
    91             updateSqrt(1, l, r, 1, n, 0);
    92         }
    93         if (opt==3){
    94             int l = read(), r = read();
    95             printf("%lld
    ",query(1, l, r, 1, n, 0));
    96         }
    97     }
    98     return 0;
    99 }

    END

  • 相关阅读:
    CodeForce20C
    2019年9月末周java面试题总结
    java复习--框架部分
    java复习--Oracle数据库
    java复习--Web部分
    java复习--基础部分
    springboot中使用poi导入excel文件
    springboot中使用poi导出excel文件
    20.java自定义注解
    Redis入门
  • 原文地址:https://www.cnblogs.com/antiquality/p/9420318.html
Copyright © 2020-2023  润新知