「SP2713」GSS4 - Can you answer these queries IV

传送门
Luogu

解题思路

区间开方以及区间求和。
考虑用线段树来做。
开方操作看似没有任何结合律可言,但这题有另外一个性质:
一个数的初始值不超过 \(10^{18}\) ,而这个数被开方6次左右就可以到1或0,并且1和0都是不需要再开方的。
所以我们记一下每个节点代表区间的最大值,若该值小于等于1,那么就不需要再进入下一层递归,否则就向下递归修改,修改次数最坏也不过是 \(O(6n)\) 左右,线段树完全没压力,于是这题就做完了。

细节注意事项

  • 咕咕咕

参考代码

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cctype>
#include <cmath>
#include <ctime>
#define rg register
using namespace std;
template < typename T > inline void read(T& s) {
    s = 0; int f = 0; char c = getchar();
    while (!isdigit(c)) f |= (c == '-'), c = getchar();
    while (isdigit(c)) s = s * 10 + (c ^ 48), c = getchar();
    s = f ? -s : s;
}

typedef long long LL;
const int _ = 100010;

int n; LL a[_], sum[_ << 2], mx[_ << 2];

inline int lc(int rt) { return rt << 1; }

inline int rc(int rt) { return rt << 1 | 1; }

inline void pushup(int rt) {
    sum[rt] = sum[lc(rt)] + sum[rc(rt)];
    mx[rt] = max(mx[lc(rt)], mx[rc(rt)]);
}

inline void build(int rt = 1, int l = 1, int r = n) {
    if (l == r) { mx[rt] = sum[rt] = a[l]; return; }
    int mid = (l + r) >> 1;
    build(lc(rt), l, mid), build(rc(rt), mid + 1, r), pushup(rt);
}

inline void update(int ql, int qr, int rt = 1, int l = 1, int r = n) {
    if (mx[rt] <= 1) return;
    if (l == r) { mx[rt] = sum[rt] = sqrt(sum[rt]); return; }
    int mid = (l + r) >> 1;
    if (ql <= mid) update(ql, qr, lc(rt), l, mid);
    if (qr > mid) update(ql, qr, rc(rt), mid + 1, r);
    pushup(rt);
}

inline LL query(int ql, int qr, int rt = 1, int l = 1, int r = n) {
    if (ql <= l && r <= qr) return sum[rt];
    int mid = (l + r) >> 1; LL res = 0;
    if (ql <= mid) res += query(ql, qr, lc(rt), l, mid);
    if (qr > mid) res += query(ql, qr, rc(rt), mid + 1, r);
    return res;
}

int main() {
#ifndef ONLINE_JUDGE
    freopen("in.in", "r", stdin);
#endif
    int Case = 0;
    while (scanf("%d", &n) != EOF) {
        printf("Case #%d:\n", ++Case);
        for (rg int i = 1; i <= n; ++i) read(a[i]);
        build();
        int q; read(q);
        for (rg int f, ql, qr; q--; ) {
            read(f), read(ql), read(qr);
            if (ql > qr) swap(ql, qr);
            if (!f) update(ql, qr);
            else printf("%lld\n", query(ql, qr));
        }
        puts("");
    }
    return 0;
}

完结撒花 \(qwq\)

原文地址:https://www.cnblogs.com/zsbzsb/p/11746530.html

时间: 2024-08-30 09:36:17

「SP2713」GSS4 - Can you answer these queries IV的相关文章

题解 SP2713 【GSS4 - Can you answer these queries IV】

用计算器算一算,就可以发现\(10^{18}\)的数,被开方\(6\)次后就变为了\(1\). 所以我们可以直接暴力的进行区间修改,若这个数已经到达\(1\),则以后就不再修改(因为\(1\)开方后还是\(1\)),用并查集和树状数组进行维护. 这个方法用了P2391 白雪皑皑的思想处理,用并查集标记该点已经不再用替换. 和我这题CF920F[SUM和REPLACE]的方法相同. \(code\): #include<bits/stdc++.h> #define maxn 500010 #de

SPOJ GSS4 Can you answer these queries IV (线段树)

题目大意: 给出N个数 0     操作   把 l -----  r之间的数全部开平方 1     操作  输出 l -----r  之间的和 思路分析: 判断区间里的数字是否全相同.如果相同, 将cov 置为该数 查询的时候和更新的时候,如果碰到cov != -1 的  就直接返回就可以了 #include <cstdio> #include <iostream> #include <algorithm> #include <cstring> #incl

SPOJ GSS4 Can you answer these queries IV

Can you answer these queries IV Time Limit: 5000ms Memory Limit: 262144KB This problem will be judged on SPOJ. Original ID: GSS464-bit integer IO format: %lld      Java class name: Main You are given a sequence A of N(N <= 100,000) positive integers.

【SP2713 GSS4 - Can you answer these queries IV】 题解

题目链接:https://www.luogu.org/problemnew/show/SP2713 真暴力啊. 开方你开就是了,开上6次就都没了. #include <cmath> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define ll long long using namespace std; const int maxn

SP2713 GSS4 - Can you answer these queries IV

传送门 \(ZHX\; TQL\) Orz 这道题目我们可以用线段树维护-- 可能有\(dalao\)会问:"线段树怎么维护区间开平方?" 而这道题的精髓就在于,它要我们维护的操作是开平方+下取整.也就是说经过一定的次数,要开平方的数会慢慢缩小为"\(1\)",这个次数是很小的,而\(\sqrt 1=1\). 所以在修改时,我们可以先查询这个区间是否全是"1",如果是,那我们就不管它,再去寻找其他的区间进行修改,如果这个区间里有其他数,我们就将这

SP2713 GSS4 - Can you answer these queries IV(线段树)

传送门 解题思路 大概就是一个数很少次数的开方会开到\(1\),而\(1\)开方还是\(1\),所以维护一个和,维护一个开方标记,维护一个区间是否全部为\(1/0\)的标记.然后每次修改时先看是否有全\(1\)或\(0\)的标记,有就不用理了,没有就暴力开方. 代码 #include<iostream> #include<cstdio> #include<cstring> #include<cmath> #define int long long using

「SP1043」GSS1 - Can you answer these queries I

传送门 Luogu 解题思路 这题就是 GSS3 的一个退化版,不带修改操作的区间最大子段和,没什么好讲的. 细节注意事项 咕咕咕 参考代码 #include <algorithm> #include <iostream> #include <cstring> #include <cstdlib> #include <cstdio> #include <cctype> #include <cmath> #include &

Spoj 2713 Can you answer these queries IV 水线段树

题目链接:点击打开链接 题意: 给定n长的序列 下面2个操作 0 x y 给[x,y]区间每个数都 sqrt 1 x y 问[x, y] 区间和 #include <stdio.h> #include <iostream> #include <algorithm> #include <string.h> #include <queue> #include <math.h> #include <vector> #includ

LibreOJ #2012. 「SCOI2016」背单词

二次联通门 : LibreOJ #2012. 「SCOI2016」背单词 /* LibreOJ #2012. 「SCOI2016」背单词 Trie + 贪心 大家都吐槽题目反人类 可我觉得还好,毕竟见的多了 不会做啊.. 正解好巧妙 考虑一下,发现一操作完全不必要,可以省去 因为所有的字符串的后缀关系会形成一个树 那么把字符串倒序插入Trie中 建树,每次向子树小的一个点转移即可 */ #include <cstdio> #include <algorithm> #include