【UOJ#228】 基础数据结构练习题
题目描述
sylvia 是一个热爱学习的女孩子,今天她想要学习数据结构技巧。
在看了一些博客学了一些姿势后,她想要找一些数据结构题来练练手。于是她的好朋友九条可怜酱给她出了一道题。
给出一个长度为 nn 的数列 AA,接下来有 mm 次操作,操作有三种:
- 对于所有的 i∈[l,r]i∈[l,r],将 AiAi 变成 Ai+xAi+x。
- 对于所有的 i∈[l,r]i∈[l,r],将 AiAi 变成 ⌊Ai‾‾√⌋⌊Ai⌋。
- 对于所有的 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 | n≤3000 |
m≤3000 | |
2 | |||
3 | |||
4 | n≤100000 | m≤100000 | 数据随机生成 |
5 | |||
6 | ti≠1 |
||
7 | |||
8 | |||
9 | |||
10 |
对于所有数据,保证有 1≤li≤ri≤n,1≤Ai,xi≤105
时间限制: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\n", query(1, 1, n)); 124 } 125 } 126 return 0; 127 }