标签:空间 highlight ++ ati head vertica data lin nbsp
sylvia 是一个热爱学习的女孩子,今天她想要学习数据结构技巧。
在看了一些博客学了一些姿势后,她想要找一些数据结构题来练练手。于是她的好朋友九条可怜酱给她出了一道题。
给出一个长度为 nn 的数列 AA,接下来有 mm 次操作,操作有三种:
作为一个不怎么熟练的初学者,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,表示操作三。
对于每个询问操作,输出一行表示答案。
5 5
1 2 3 4 5
1 3 5 2
2 1 4
3 2 4
2 3 5
3 1 5
5
6
见样例数据下载。
测试点编号 | nn 的规模 | mm 的规模 | 其他约定 |
---|---|---|---|
1 | n≤3000n≤3000 | m≤3000m≤3000 | |
2 | |||
3 | |||
4 | n≤100000n≤100000 | m≤100000m≤100000 | 数据随机生成 |
5 | |||
6 | ti≠1ti≠1 | ||
7 | |||
8 | |||
9 | |||
10 |
对于所有数据,保证有 1≤li≤ri≤n,1≤Ai,xi≤1051≤li≤ri≤n,1≤Ai,xi≤105
时间限制:1s1s
空间限制:256MB
总结:这种题一般是考虑什么暴力姿势不会炸
可以证明两个数一直开根号, 直到相等为止,最多loglog次
因此考虑暴力,一直暴力开根号到两数相等,然后相等后就可以转化为区间加
有一种特殊情况 如
9 8
sqrt(9) = 3, sqrt(8) = 2
9 - 8 = 3 - 2
开根号后, 两数差值不变,这样的话,暴力就会被卡掉, 特判一下这种情况,转化为区间加
全得开 long long
#include <bits/stdc++.h> using namespace std; #define LL long long const int maxn = 4e5 + 7; LL sum[maxn], tag[maxn], Max[maxn], Min[maxn]; int n, m, a[maxn]; int read() { int x = 0, f = 1; char ch = getchar(); while(ch < ‘0‘ || ch > ‘9‘) { if(ch == ‘-‘) f = -1; ch = getchar();} while(ch >= ‘0‘ && ch <= ‘9‘) { x = x * 10 + ch - 48; ch = getchar();} return x* f; } LL mmax(LL a, LL b) {return a > b ?a :b;} LL mmin(LL a, LL b) {return a < b ?a :b;} void pushdown(int o, int l, int r) { if(tag[o]) { int mid = (l + r) >> 1; tag[o << 1] += tag[o]; tag[o << 1 | 1] += tag[o]; sum[o << 1] += (mid - l + 1) * tag[o]; sum[o << 1 | 1] += (r - mid) * tag[o]; Max[o << 1] += tag[o]; Max[o << 1 | 1] += tag[o]; Min[o << 1] += tag[o]; Min[o << 1 | 1] += tag[o]; tag[o] = 0; } } void update(int o) { sum[o] = sum[o << 1] + sum[o << 1 | 1]; Max[o] = mmax(Max[o << 1], Max[o << 1 | 1]); Min[o] = mmin(Min[o << 1], Min[o << 1 | 1]); } void Build(int o, int l, int r) { if(l == r) { sum[o] = Max[o] = Min[o] = a[l]; return; } int mid = (l + r) >> 1; Build(o << 1, l, mid); Build(o << 1 | 1, mid + 1, r); update(o); } LL Query(int o, int l, int r, int ql, int qr) { if(ql <= l && r <= qr) return sum[o]; int mid = (l + r) >> 1; LL res = 0; pushdown(o, l, r); if(ql <= mid) res += Query(o << 1, l, mid, ql, qr); if(qr > mid) res += Query(o << 1 | 1, mid + 1, r, ql, qr); return res; } void Modify(int o, int l, int r, int ql, int qr, LL z) { if(ql <= l && r <= qr) { sum[o] += z * (r - l + 1); tag[o] += z; Max[o] += z; Min[o] += z; return; } int mid = (l + r) >> 1; pushdown(o, l, r); if(ql <= mid) Modify(o << 1, l, mid, ql, qr, z); if(qr > mid) Modify(o << 1 | 1, mid + 1, r, ql, qr, z); update(o); } void Sqrt(int o, int l, int r, int ql, int qr) { if(ql <= l && r <= qr) { if((Max[o] - Min[o] == (LL)sqrt(Max[o]) - (LL)sqrt(Min[o])) || (Max[o] == Min[o])) { LL z = (LL)sqrt(Max[o]) - Max[o]; sum[o] += z * (r - l + 1); Max[o] += z; Min[o] += z; tag[o] += z; return; } } pushdown(o, l, r); int mid = (l + r) >> 1; if(ql <= mid) Sqrt(o << 1, l, mid, ql, qr); if(qr > mid) Sqrt(o << 1 | 1, mid + 1, r, ql, qr); update(o); } int main() { n = read(); m = read(); for (register int i = 1; i <= n; ++i) a[i] = read(); Build(1, 1, n); while(m--) { int op, x, y; op = read(); x = read(); y = read(); LL z; switch(op) { case 1: z = read(); Modify(1, 1, n, x, y, z); break; case 2: Sqrt(1, 1, n, x, y); break; case 3: printf("%lld\n", Query(1, 1, n, x, y)); } } return 0; }
标签:空间 highlight ++ ati head vertica data lin nbsp
原文地址:https://www.cnblogs.com/oi-forever/p/9190055.html