首页 > 技术文章 > P4145 上帝造题的七分钟2 / 花神游历各国

Garen-Wang 2018-12-22 17:54 原文

能用线段树的就不要用分块!真香警告!

这道题也很清晰:区间开方、区间求和。

掏出计算器,发现就算最大的\(10^{12}\),按6次开方就已经变成1!

所以我们的思路就是跳过那些已经都是1或0的区间,因为它们拿去开方一点意义都没有。

区间开方不需要打懒标记,因为最多就是\(600000\)次单点修改,完全可以跑。

当一个区间最大值为1或者为0时,跳过这个区间。这个操作将给你省下一大堆时间。

代码:

#include<iostream>
#include<cmath>
using std::cin;
using std::cout;
using std::endl;
#define ll long long

const ll maxn = 100005;
ll a[maxn];
ll n, m;

struct segTree
{
    ll maxv[maxn << 2], sum[maxn << 2], lazy[maxn << 2];
    #define lson (root << 1)
    #define rson (root << 1 | 1)
    void pushup(ll root)
    {
        maxv[root] = std::max(maxv[lson], maxv[rson]);
        sum[root] = sum[lson] + sum[rson];
    }
    void pushdown(ll root, ll l, ll r)
    {
        if(lazy[root] != 0)
        {
            ll &x = lazy[root];
            ll mid = (l + r) >> 1;
            sum[lson] += x * (mid - l + 1);
            maxv[lson] += x;
            lazy[lson] += x;
            sum[rson] += x * (r - mid);
            maxv[rson] += x;
            lazy[rson] += x;
            x = 0;
        }
    }
    void build(ll root, ll l, ll r)
    {
        lazy[root] = 0;
        if(l == r) maxv[root] = sum[root] = a[l];
        else
        {
            int mid = (l + r) >> 1;
            build(lson, l, mid);
            build(rson, mid + 1, r);
            pushup(root);
        }
    }
    void update(ll root, ll l, ll r, ll x, ll y)
    {
        if(r < x || y < l) return;
        if(maxv[root] == 1 || maxv[root] == 0) return;
        if(l == r)
        {
            sum[root] = maxv[root] = sqrt(sum[root]);
        }
        else
        {
            pushdown(root, l, r);
            ll mid = (l + r) >> 1;
            update(lson, l, mid, x, y);
            update(rson, mid + 1, r, x, y);
            pushup(root);
        }
    }
    ll query(ll root, ll l, ll r, ll x, ll y)
    {
        if(r < x || y < l) return 0;
        if(x <= l && r <= y) return sum[root];
        pushdown(root, l, r);
        int mid = (l + r) >> 1;
        return query(lson, l, mid, x, y) + query(rson, mid + 1, r, x, y);
    }
} seg;

int main()
{
    std::ios::sync_with_stdio(false);
    cin >> n;
    for(ll i = 1; i <= n; i++) cin >> a[i];
    seg.build(1, 1, n);
    cin >> m;
    while(m--)
    {
        ll k, l, r; cin >> k >> l >> r;
        if(l > r) std::swap(l, r);
        if(k)
        {
            cout << seg.query(1, 1, n, l, r) << endl;
        }
        else
        {
            seg.update(1, 1, n, l, r);
        }
    }
    return 0;
}

推荐阅读