hdu5828 Rikka with Sequence

传送门:http://acm.hdu.edu.cn/showproblem.php?pid=5828

【题解】

考虑bzoj3211 花神游历各国,只是多了区间加操作。

考虑上题写法,区间全为1打标记。考虑推广到这题:如果一个区间max开根和min开根相同,区间覆盖标记。

巧的是,这样复杂度是错的!

e.g:

$n = 10^5, m = 10^5$

$a[] = \{1, 2, 1, 2, ... , 1, 2\}$

$operation = \{ "1~1~n~2", "2~1~n", "1~1~n~2", "2~1~n", ... \}$

然后发现没有可以合并的,每次都要暴力做,复杂度就错了。

考虑对于区间的$max-min \leq 1$的情况维护:

当$max=min$,显然直接做即可。

当$max=min+1$,如果$\sqrt{max} = \sqrt{min}$,那么变成区间覆盖;否则$\sqrt{max} = \sqrt{min} + 1$,变成区间加法。

都是线段树基本操作,所以可以做。

下面证明复杂度为什么是对的:

时间复杂度$O(nlog^2n)$。

# include <math.h>
# include <stdio.h>
# include <string.h>
# include <iostream>
# include <algorithm>
// # include <bits/stdc++.h>

# ifdef WIN32
# define LLFORMAT "%I64d"
# else
# define LLFORMAT "%lld"
# endif

using namespace std;

typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
const int N = 1e5 + 10;
const int mod = 1e9+7;

inline int getint() {
    int x = 0; char ch = getchar();
    while(!isdigit(ch)) ch = getchar();
    while(isdigit(ch)) x = (x<<3) + (x<<1) + ch - ‘0‘, ch = getchar();
    return x;
}

int n, a[N];

const int SN = 262144 + 5;
struct SMT {
    ll mx[SN], mi[SN], s[SN], tag[SN], cov[SN];
    # define ls (x<<1)
    # define rs (x<<1|1)
    inline void up(int x) {
        mx[x] = max(mx[ls], mx[rs]);
        mi[x] = min(mi[ls], mi[rs]);
        s[x] = s[ls] + s[rs];
    }
    inline void pushtag(int x, int l, int r, ll tg) {
        mx[x] += tg, mi[x] += tg;
        s[x] += tg * (r-l+1); tag[x] += tg;
    }
    inline void pushcov(int x, int l, int r, ll cv) {
        mx[x] = cv, mi[x] = cv;
        s[x] = cv * (r-l+1); cov[x] = cv; tag[x] = 0;
    }
    inline void down(int x, int l, int r) {
        register int mid = l+r>>1;
        if(cov[x]) {
            pushcov(ls, l, mid, cov[x]);
            pushcov(rs, mid+1, r, cov[x]);
            cov[x] = 0;
        }
        if(tag[x]) {
            pushtag(ls, l, mid, tag[x]);
            pushtag(rs, mid+1, r, tag[x]);
            tag[x] = 0;
        }
    }
    inline void build(int x, int l, int r) {
        tag[x] = cov[x] = 0;
        if(l == r) {
            mx[x] = mi[x] = s[x] = a[l];
            return ;
        }
        int mid = l+r>>1;
        build(ls, l, mid); build(rs, mid+1, r);
        up(x);
    }
    inline void edt(int x, int l, int r, int L, int R, int d) {
        if(L <= l && r <= R) {
            pushtag(x, l, r, d);
            return ;
        }
        down(x, l, r);
        int mid = l+r>>1;
        if(L <= mid) edt(ls, l, mid, L, R, d);
        if(R > mid) edt(rs, mid+1, r, L, R, d);
        up(x);
    }
    inline void doit(int x, int l, int r) {
        if(mx[x] == mi[x]) {
            register ll t = mx[x];
            pushtag(x, l, r, ll(sqrt(t)) - t);
            return ;
        }
        if(mx[x] == mi[x] + 1) {
            register ll pmx = ll(sqrt(mx[x])), pmi = ll(sqrt(mi[x]));
            if(pmx == pmi) pushcov(x, l, r, pmx);
            else pushtag(x, l, r, pmx - mx[x]);    // mx[x] = mi[x] + 1
            return ;
        }
        down(x, l, r);
        int mid = l+r>>1;
        doit(ls, l, mid); doit(rs, mid+1, r);
        up(x);
    }

    inline void edt(int x, int l, int r, int L, int R) {
        if(L <= l && r <= R) {
            doit(x, l, r);
            return ;
        }
        down(x, l, r);
        int mid = l+r>>1;
        if(L <= mid) edt(ls, l, mid, L, R);
        if(R > mid) edt(rs, mid+1, r, L, R);
        up(x);
    }

    inline ll sum(int x, int l, int r, int L, int R) {
        if(L <= l && r <= R) return s[x];
        down(x, l, r);
        int mid = l+r>>1; ll ret = 0;
        if(L <= mid) ret += sum(ls, l, mid, L, R);
        if(R > mid) ret += sum(rs, mid+1, r, L, R);
        return ret;
    }
}T;

inline void sol() {
    n = getint(); register int Q = getint(), op, l, r, x;
    for (int i=1; i<=n; ++i) a[i] = getint();
    T.build(1, 1, n);
    while(Q--) {
        op = getint(), l = getint(), r = getint();
        if(op == 1) {
            x = getint();
            T.edt(1, 1, n, l, r, x);
        } else if(op == 2) T.edt(1, 1, n, l, r);
        else printf(LLFORMAT "\n", T.sum(1, 1, n, l, r));
    }
}

int main() {
    int T = getint();
    while(T--) sol();
    return 0;
}

时间: 2024-11-03 05:42:03

hdu5828 Rikka with Sequence的相关文章

HDU 5828 Rikka with Sequence(线段树 开根号)

Rikka with Sequence Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 2777    Accepted Submission(s): 503 Problem Description As we know, Rikka is poor at math. Yuta is worrying about this situati

【HDU 5828】Rikka with Sequence(线段树)

[HDU 5828]Rikka with Sequence(线段树) Rikka with Sequence Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 2311    Accepted Submission(s): 391 Problem Description As we know, Rikka is poor at math.

判断相同区间(lazy) 多校8 HDU 5828 Rikka with Sequence

1 // 判断相同区间(lazy) 多校8 HDU 5828 Rikka with Sequence 2 // 题意:三种操作,1增加值,2开根,3求和 3 // 思路:这题与HDU 4027 和HDU 5634 差不多 4 // 注意开根号的话,遇到极差等于1的,开根号以后有可能还是差1.如 5 // 2 3 2 3... 6 // 8 9 8 9... 7 // 2 3 2 3... 8 // 8 9 8 9... 9 // 剩下就是遇到区间相等的话,就直接开根号不往下传 10 11 12

hdu 5204 Rikka with sequence 智商不够系列

Rikka with sequence Time Limit: 1 Sec  Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=5204 Description 众所周知,萌萌哒六花不擅长数学,所以勇太给了她一些数学问题做练习,其中有一道是这样的:现在有一个序列,因为这个序列很任性,开始时空的.接下来发生了n个事件,每一个事件是以下两种之一:1.勇太利用黑炎龙的力量在序列的开头.结尾以及每相邻两个元素之间都插入

hdu 5204 Rikka with sequence

题意: 众所周知,萌萌哒六花不擅长数学,所以勇太给了她一些数学问题做练习,其中有一道是这样的: 如果一个无重边无自环的无向图的每个联通块都存在一条回路经过这个联通分量所有边一次且仅一次,那么就称这个无向图是优美的.请问有n个点且边数不少于m的优美的图有多少个?(在这题中,我们认为这n个点是本质不同的) 当然,这个问题对于萌萌哒六花来说实在是太难了,你可以帮帮她吗? 限制: 1 <= n <= 1e5; 1 <= L <= R <= 1e18; 1 <= w <=

hdu 5204 Rikka with sequence(BestCoder Round #37)

Rikka with sequence                                                        Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 378    Accepted Submission(s): 75 Problem Description As we know, Rikk

2016暑假多校联合---Rikka with Sequence (线段树)

2016暑假多校联合---Rikka with Sequence (线段树) Problem Description As we know, Rikka is poor at math. Yuta is worrying about this situation, so he gives Rikka some math tasks to practice. There is one of them: Yuta has an array A with n numbers. Then he make

HDU 5828 Rikka with Sequence

好久没写线段树了,这题作为一个回味.. 第一种操作的话,就是一个延迟标记. 第二种操作可以暴力更新下去,但是有一个优化,如果某区间内所有值都是一样的,那么到此结束,不要继续往下面暴力更新了. 这样一来的话,pushDown的时候要注意一下,如果该区间内所有值都一样,那么延迟标记不要往下扔了,直接把该区间的信息传下去.如果该区间内所有值不一样,将延迟标记扔下去. 总体难度不算大,仔细一些就能AC. 不过这样的方法是水过去的. 10W个2 3 2 3 2 3 2 3..... 10W次操作 +6 s

Rikka with Sequence

题意: 给一长度为n的序列,维护三个操作:区间开根,区间加,区间求和. 解法: 注意到本题关键在于区间开根: 对于一个数字,只要进行$O(loglogT)$次开根即会变为1. 考虑线段树,对于线段数上的点维护$maxv$,$minv$. 对于$[\sqrt{maxv}] = [\sqrt{minv}]$的点我们直接执行区间染色. 如果我们在开根时经过这个点则有$maxv - minv$减小,且只会经过$O(loglog(maxv-minv))$次. 考虑区间加的操作,相当于只是让$O(logn)