zoukankan      html  css  js  c++  java
  • 【UOJ#228】 基础数据结构练习题

    题目描述

    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,m。

    接下来一行 n 个数 Ai

    接下来 m 行中,第 i 行第一个数 ti 表示操作类型:

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

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

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

    输出格式

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

    样例一

    input

    5 5
    1 2 3 4 5
    1 3 5 2
    2 1 4
    3 2 4
    2 3 5
    3 1 5
    
    

    output

    5
    6
    
    

    样例二

    见样例数据下载。

    限制与约定

    测试点编号n 的规模m 的规模其他约定
    1 n3000
    m≤3000  
    2
    3
    4 n≤100000 m≤100000 数据随机生成
    5
    6 ti1
    7
    8  
    9
    10

    对于所有数据,保证有 1lirin,1Ai,xi105

    时间限制:1s

    空间限制:256MB

    题解

    orz 北大爷yyy。

    用线段树维护区间的最大、最小值和答案。每次区间取根号的时候我们发现区间的极差都会减少,最后会减少到0。可以证明这个次数是loglogn级别的(开根相当于指数一直除以2),所以可以暴力递归进去改。但是区间加会导致区间的极差发生变化也有可能不变。所以我们在做开根号的时候只有在区间的极差会变的情况下我们暴力递归进去改,否则就直接区间减。可以证明这样的复杂度是NlogNloglogN的。

    代码

      1 #include <cstdio>
      2 #include <cmath>
      3 
      4 #define R register
      5 #define maxn 1048586
      6 typedef long long ll;
      7 int a[maxn];
      8 ll sum[maxn], mn[maxn], mx[maxn], tag[maxn], mnnum[maxn], mxnum[maxn];
      9 #define dmin(_a, _b) ((_a) < (_b) ? (_a) : (_b))
     10 #define dmax(_a, _b) ((_a) > (_b) ? (_a) : (_b))
     11 inline void update(R int o)
     12 {
     13     sum[o] = sum[o << 1] + sum[o << 1 | 1];
     14     mn[o] = dmin(mn[o << 1], mn[o << 1 | 1]);
     15     mx[o] = dmax(mx[o << 1], mx[o << 1 | 1]);
     16 }
     17 inline void pushdown(R int o, R int l, R int r, R int mid)
     18 {
     19     if (tag[o] != 0)
     20     {
     21         sum[o << 1] += 1ll * tag[o] * (mid - l + 1);
     22         sum[o << 1 | 1] += 1ll * tag[o] * (r - mid);
     23         mn[o << 1] += tag[o]; mx[o << 1] += tag[o];
     24         mn[o << 1 | 1] += tag[o]; mx[o << 1 | 1] += tag[o];
     25         tag[o << 1] += tag[o];
     26         tag[o << 1 | 1] += tag[o];
     27         tag[o] = 0;
     28     }
     29 }
     30 void build(R int o, R int l, R int r)
     31 {
     32     if (l == r)
     33     {
     34         mn[o] = mx[o] = sum[o] = a[l];
     35         mnnum[o] = mxnum[o] = 1;
     36         return ;
     37     }
     38     R int mid = l + r >> 1;
     39     build(o << 1, l, mid);
     40     build(o << 1 | 1, mid + 1, r);
     41     update(o);
     42 }
     43 int ql, qr, qv;
     44 void modify1(R int o, R int l, R int r)
     45 {
     46     if (ql <= l && r <= qr)
     47     {
     48         tag[o] += qv;
     49         sum[o] += 1ll * qv * (r - l + 1);
     50         mx[o] += qv;
     51         mn[o] += qv;
     52         return ;
     53     }
     54     R int mid = l + r >> 1;
     55     pushdown(o, l, r, mid);
     56     if (ql <= mid) modify1(o << 1, l, mid);
     57     if (mid < qr) modify1(o << 1 | 1, mid + 1, r);
     58     update(o);
     59 }
     60 inline bool check(R ll x)
     61 {
     62     return (ll) sqrt(x) * (ll) sqrt(x) == x;
     63 }
     64 void modify2(R int o, R int l, R int r)
     65 {
     66     if (ql <= l && r <= qr)
     67     {
     68         if (mx[o] == mn[o] || (mx[o] - mn[o] == 1 && check(mx[o])))
     69         {
     70             R ll p = mx[o] - (ll) sqrt(mx[o]);
     71             tag[o] -= p;
     72             sum[o] -= p * (r - l + 1);
     73             mx[o] -= p;
     74             mn[o] -= p;
     75         }
     76         else
     77         {
     78             R int mid = l + r >> 1;
     79             pushdown(o, l, r, mid);
     80             modify2(o << 1, l, mid);
     81             modify2(o << 1 | 1, mid + 1, r);
     82             update(o);
     83         }
     84         return ;
     85     }
     86     R int mid = l + r >> 1;
     87     pushdown(o, l, r, mid);
     88     if (ql <= mid) modify2(o << 1, l, mid);
     89     if (mid < qr) modify2(o << 1 | 1, mid + 1, r);
     90     update(o);
     91 }
     92 inline ll query(R int o, R int l, R int r)
     93 {
     94     if (ql <= l && r <= qr) return sum[o];
     95     R int mid = l + r >> 1; R ll ret = 0;
     96     pushdown(o, l, r, mid);
     97     if (ql <= mid) ret += query(o << 1, l, mid);
     98     if (mid < qr) ret += query(o << 1 | 1, mid + 1, r);
     99     return ret;
    100 }
    101 int main()
    102 {
    103     R int n, m; scanf("%d%d", &n, &m);
    104     for (R int i = 1; i <= n; ++i) scanf("%d", a + i);
    105     build(1, 1, n);
    106     for (R int i = 1; i <= m; ++i)
    107     {
    108         R int opt, l, r; scanf("%d%d%d", &opt, &l, &r);
    109         if (opt == 1)
    110         {
    111             R int x; scanf("%d",  &x);
    112             ql = l; qr = r; qv = x;
    113             modify1(1, 1, n);
    114         }
    115         else if (opt == 2)
    116         {
    117             ql = l; qr = r;
    118             modify2(1, 1, n);
    119         }
    120         else
    121         {
    122             ql = l; qr = r;
    123             printf("%lld
    ", query(1, 1, n));
    124         }
    125     }
    126     return 0;
    127 }
  • 相关阅读:
    写个简单的搜索引擎
    C++中的三种继承关系
    《深度探索C++对象模型》调用虚函数
    一次数据库优化的对话
    读后感:你的灯亮着吗
    Linux Shell 截取字符串
    一次关于知识储备的思考
    哈夫曼树与哈夫曼编码
    二叉查找树
    jar中没有注清单属性
  • 原文地址:https://www.cnblogs.com/cocottt/p/7105238.html
Copyright © 2011-2022 走看看