zoukankan      html  css  js  c++  java
  • [ACM]数列分块1-9

    14____数列分块

    14.1____数列分块1(区间加法,单点查询)

    image-20210803104118041

    题解:

    ​ 这个题就是数列分块的板子题,对区间做区间修改单点查询,区间修改为区间加法,线段树同样可以做,但是代码就很复杂了,我们用 tag 来维护分块区间的相同和

    ​ 在update的时候,如果在同一区间内,那么我们直接 (O(n))​​​解决 ,如果不在的话,那么位于左端和右端的区间,我们都直接 (O(n))​​​ 处理, 在中间的区间,我们直接同一加到 tag 上,这 tag 数组有点像 线段树的 lazy标记,但是不会 push_down,查询的时候,我们直接叠加上去就可以了。

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N = 5e4 + 10;
    
    int a[N],s[N],tag[N],len,id[N];
    
    void add(int l,int r,int c)
    {
        int sid = id[l] , eid = id[r];
        if( sid == eid ){
            for(int i = l ;i <= r; i++){
                a[i] += c, s[sid] += c;
            }
            return ;
        }
    
        for(int i = l ; id[i] == sid ; i++) a[i] += c,s[ sid ] += c;
        for(int i = sid + 1 ; i < eid ; i++) tag[i] += c,s[ i ] += c * len;
        for(int i = r ; id[i] == eid ; i--) a[i] += c,s[eid] += c;
    }
    
    int query(int x)
    {
        return a[x] + tag[ id[x] ];
    }
    
    int main()
    {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
        cout.tie(nullptr);
    
        int n;
        cin >> n;
        len = sqrt(n);
    
        for(int i = 1; i <= n ; i++){
            cin >> a[i];
            id[i] = (i - 1) / len + 1;
            s[ id[i] ] += a[i];
        }
    
        for(int i = 0 ; i < n ; i++){
            int op,x,y,z;
            cin >> op >> x >> y >> z;
            if( op == 0 ){
                add(x,y,z);
            }else{
                cout << query(y) << endl;
            }
        }
        return 0;
    }
    

    14.2____数列分块2

    image-20210803104611858

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N = 5e5 + 10;
    int a[N],len,id[N],tag[N],vec[N];
    
    /// id * len 当前块最后一个元素
    /// (id - 1) * len + 1 当前块的第一个元素
    /// 注意lower_bound 是左闭右开 (取不到第二个值)
    /// 开区间使用符号小括号()表示,闭区间使用符号中括号[]表示
    void reset(int tes,int tee)   /// x为所在分块的编号
    {
        for(int i = tes ; i <= tee ; i++)   vec[i] = a[i];
        sort(vec + tes,vec + tee + 1);
    }
    
    void update(int l,int r,int c)
    {
        int sid = id[l],eid =  id[r];
    
        if(sid == eid){
            for(int i = l ; i <= r; i++)    a[i] += c;
            reset( (sid - 1)*len +1 ,sid *len );
            return ;
        }
        ///
        for(int i = l; id[i] == sid ; i++)    a[i] += c;
        reset( (sid - 1)*len +1 ,sid *len );
    
        for(int i = sid + 1 ; i < eid ; i++)    tag[i] += c;
    
        for(int i = r ; id[i] == eid ; i--)  a[i] += c;
        reset( (eid - 1)*len +1 ,eid *len );
    
    }
    
    int query(int l,int r,int x)
    {
        int sid = id[l], eid = id[r] , cnt = 0;
    
        if( sid == eid){
            for(int i = l ; i <= r; i++)
                if( a[i] + tag[ id[i] ] < x ) cnt++;
            return cnt;
        }
        ///
        int te = sid * len ;
        for(int i = l ; i <= te ; i++)
            if( a[i] + tag[ sid ] < x ) cnt ++;
    
        for(int i = sid + 1; i < eid ; i++){
            int tes = (i - 1)*len + 1, tee = i *len;
            cnt += int( lower_bound( vec + tes , vec + tee + 1, x - tag[i]) - vec - tes );
        }
    
        te = (eid - 1)  * len + 1;
        for(int i = te ; i <= r; i++)
            if( a[i] + tag[ eid ] < x ) cnt++;
    
        return cnt;
    
    }
    
    int main()
    {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
        cout.tie(nullptr);
    
        int n;
        cin >> n;
        len = sqrt(n);
    
        for(int i = 1; i <= n ; i++){
            cin >> a[i];
            id[i] = (i - 1) /len + 1;
        }
    
        for(int i = 1 ; i <= id[n] ; i++ ){
            reset((i - 1)*len + 1, i * len);
            /// 注意如果是最后一个分块,要单独弄
            if (i == id[n]) {
                reset((i - 1)*len + 1, n);
            }
        }
    
        for(int i = 0; i < n ; i++){
            int op,x,y,z;
            cin >> op >> x >> y >> z;
            if( op == 0 ){
                update(x,y,z);
            }else{
                cout << query(x,y,z*z) <<endl;
            }
        }
    
        return 0;
    }
    
    

    线段树

    #include <bits/stdc++.h>
    #define ls (rt<<1)
    #define rs (rt<<1|1)
    #define Mid ((T[rt].l + T[rt].r)>>1)
    #define L ( T[rt].l)
    #define R (T[rt].r)
    using namespace std;
    
    const int N = 5e4 + 10;
    void file() {
    #ifdef ONLINE_JUDGE
    #else
        freopen("d:/workProgram/test.in", "r", stdin);
    #endif
    }
    
    struct Node {
        int l, r;
        int ma, mi;
        int lazy ;
    } T[N << 2];
    
    int a[N];
    
    void up(int rt) {
        T[rt].ma = max(T[ls].ma, T[rs].ma);
        T[rt].mi = min(T[ls].mi, T[rs].mi);
    }
    
    void down(int rt) {
        if (T[rt].lazy != 0) {
            T[ls].lazy += T[rt].lazy;
            T[rs].lazy += T[rt].lazy;
            T[ls].ma += T[rt].lazy;
            T[rs].ma += T[rt].lazy;
            T[ls].mi += T[rt].lazy;
            T[rs].mi += T[rt].lazy;
            T[rt].lazy = 0;
        }
    }
    
    void build(int rt, int l, int r) {
        T[rt] = {l, r, 0, 0, 0};
    
        if (l == r) {
            T[rt].ma = T[rt].mi = a[l];
            return ;
        }
    
        int mid = (l + r) >> 1;
        build(ls, l, mid), build(rs, mid + 1, r);
        up(rt);
    }
    
    void rangeUpdate(int rt, int l, int r, int val) {
        if (l <= L && r >= R) {
            T[rt].ma += val;
            T[rt].mi += val;
            T[rt].lazy += val;
            return ;
        }
    
        down(rt);
    
        if (l <= Mid)
            rangeUpdate(ls, l, r, val);
    
        if (r > Mid)
            rangeUpdate(rs, l, r, val);
    
        up(rt);
    }
    
    int rangeQuery(int rt, int l, int r, int x) {
        if (T[rt].mi >= x)
            return 0;
    
        if (l <= L  && r >= R && T[rt].ma < x) {
            return T[rt].r - T[rt].l + 1;
        }
    
        down(rt);
        int cnt = 0;
    
        if (l <= Mid)
            cnt += rangeQuery(ls, l, r, x);
    
        if (r > Mid)
            cnt += rangeQuery(rs, l, r, x);
    
        return cnt;
    }
    
    int main() {
    
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
        cout.tie(nullptr);
        //file();
        int n;
        cin >> n;
    
        for (int i = 1 ; i <= n ; i++) {
            cin >> a[i];
        }
    
        build(1, 1, n);
    
        for (int i = 0; i < n ; i++) {
            int op, l, r, x;
            cin >> op >> l >> r >> x;
    
            //cout << "--"<< i <<endl;
            if (op == 0) {
                rangeUpdate(1, l, r, x);
            } else {
                cout << rangeQuery(1, l, r, x * x) << endl;
            }
        }
    
        //system("pause");
    
        return 0;
    }
    

    14.3____数列分块3(求区间中比数x,小的第一个数)

    线段树 TLE了...可能是维护最大值和最小值,必须要递归到最深才可以更新答案,他数据全是查询,就把线段树卡死了...

    还是贴一下代码,我看了统计,前面的没有一个是线段树

    #include <bits/stdc++.h>
    #define ls (rt<<1)
    #define rs (rt<<1|1)
    #define Mid ( (T[rt].l + T[rt].r) >> 1)
    #define L (T[rt].l)
    #define R (T[rt].r)
    #define INF  (-1)*0x3f3f3f3f3f
    using namespace std;
    
    void file()
    {
        #ifdef ONLINE_JUDGE
        #else
            freopen( "d:/workProgram/test.in","r",stdin );
        #endif
    }
    
    
    typedef long long ll;
    const ll N = 1e5 + 10;
    
    struct Node
    {
        ll l,r;
        ll ma,mi,lazy;
    }T[N << 2];
    
    ll a[N],ans;   /// ans = -1*(0x3f3f3f3f);
    
    void push_up(ll rt)
    {
        T[rt].ma = max( T[ls].ma , T[rs].ma );
        T[rt].mi = min( T[ls].mi , T[rs].mi );
    }
    
    void push_down(ll rt)
    {
        if( T[rt].lazy != 0 ){
            T[ls].ma += T[rt].lazy;
            T[rs].ma += T[rt].lazy;
            T[ls].mi += T[rt].lazy;
            T[rs].mi += T[rt].lazy;
            T[ls].lazy += T[rt].lazy;
            T[rs].lazy += T[rt].lazy;
            T[rt].lazy = 0;
        }
    }
    
    void build(ll rt,ll l,ll r)
    {
        T[rt] = {l,r,0,0,0};
        if(l == r){
            T[rt].ma = T[rt].mi = a[l];
            //cout << "LL:" << l << "a:" << a[l] <<endl;
            return;
        }
    
        build(ls,l,Mid),build(rs,Mid+1,r);
        push_up(rt);
        //cout<< "l:" << L << "R:" << R << "ma:" << T[rt].ma <<endl;
    }
    
    void update(ll rt,ll l,ll r,ll val)
    {
        if( l <= L && r >= R ){
            T[rt].ma += val;
            T[rt].mi += val;
            T[rt].lazy += val;
            return ;
        }
    
        push_down(rt);
        if( l <= Mid )update(ls,l,r,val);
        if( r > Mid) update(rs,l,r,val);
        push_up(rt);
    }
    
    void query(ll rt,ll l,ll r,ll val)
    {
        if( T[rt].mi > val || T[rt].ma < ans) return ;
        if( l <= L && r >= R && T[rt].ma < val ){
            ans = max( ans , T[rt].ma);
            return ;
        }
        if( l <= L && r >= R && L == R && T[rt].ma >= val )   return ;
        if( R < l || L > r || L == R) return ;
        //cout<< "l:" << L << "R:" << R << "ma:" << T[rt].ma <<endl;
    
        push_down(rt);
        if( l <= Mid ) query(ls,l,r,val);
        if( r >= Mid ) query(rs,l,r,val);
        push_up(rt);
    
    }
    
    int main()
    {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
        cout.tie(nullptr);
        //file();
        ll n;
        cin >> n;
    
        for(int i = 1; i <= n ;i++){
            cin >> a[i];
        }
    
        build(1,1,n);
    
        for(int i = 0 ; i < n ;i++){
            int op,x,y,z;
            cin >> op >> x >> y >> z;
            if( op == 0 ){
                update(1,x,y,z);
            }else{
                ans = INF;
                query(1,x,y,z);
                //cout << "ans:" << ans << endl;
                if( ans == INF ){
                    cout << -1 <<endl;
                }else{
                    cout << ans <<endl;
                }
            }
        }
    
        return 0;
    }
    

    14.5____数列分块5(区间开方,区间求和)

    我的自己的做法是,开两个数组来维护,sum[]维护区间和,num[]来维护区间开了几次方

    num[]的由来是因为 $$2^{32}$$ 大小的数,最多开7次就到1了,之后就没必要开了,所以在add中,对于一个整块如果 num[i] > 7 || sum[i] <= len 那么我们对这个块就不需要进行操作了

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N = 1e5 + 10;
    
    int a[N], sum[N], num[N], id[N], len;
    
    void down(int l, int r) {
        for (int i = l; i <= r;  i++)
            a[i] = sqrt(a[i]);
    }
    
    int get(int l, int r) {
        int res = 0 ;
    
        for (int i = l ; i <= r; i++)
            res += a[i];
    
        return res;
    }
    
    void update(int l, int r) {
        int L = id[l], R = id[r];
    
        if (L == R) {
            for (int i = l ; i <= r; i++)
                a[i] = sqrt(a[i]);
    
            return ;
        }
    
        for (int i = l ; id[i] == L ; i++)
            a[i] = sqrt(a[i]);
    
        for (int i = r ; id[i] == R ; i--)
            a[i] = sqrt(a[i]);
    
        sum[L] = get((L - 1) * len + 1, L * len);
        sum[R] = get((R - 1) * len + 1, R * len);
    
        for (int i = L + 1; i < R; i ++) {
            if (num[i] > 7 || sum[i] <= len)
                continue;
            else {
                down((i - 1)*len + 1, i * len);
                num[i]++;
                sum[i] = get((i - 1) * len + 1, i * len);
            }
        }
    }
    
    int query(int l, int r) {
        int L = id[l], R = id[r], res = 0;
    
        if (L == R) {
            for (int i = l ; i <= r ; i++)
                res += a[i];
    
            return res;
        }
    
        for (int i = l ; id[i] == L ; i++)
            res += a[i];
    
        for (int i = r ; id[i] == R ; i--)
            res += a[i];
    
        for (int i = L + 1; i < R; i ++)
            res += sum[i];
    
        return res;
    }
    
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
        cout.tie(nullptr);
    
        int n;
        cin >> n;
        len = sqrt(n);
    
        for (int i = 1; i <= n; i++) {
            cin >> a[i];
            id[i] = (i - 1) / len + 1;
            sum[ id[i] ] += a[i];
        }
    
        for (int i = 0 ; i < n ; i++) {
            int op, x, y, z;
            cin >> op >> x >> y >> z;
    
            if (op == 0) {
                update(x, y);
            } else {
                cout << query(x, y) << "
    ";
            }
        }
    
        return 0;
    }
    

    另一个dalao的做法提交记录 #601465 - LibreOJ (loj.ac)

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N = 1e5+10, M = 500;
    int a[N],ma[M],L[M],R[M],id[N],len,sum[M];
    
    inline void update_sum(int l,int r, int k)
    {
        for(int i = l ; i <= r; i ++)   sum[k] -= a[i], a[i] = sqrt(a[i]),sum[k] += a[i];
    }
    
    inline void update_max(int k)
    {
        ma[k] = sqrt( ma[k] );
        for(int i = L[k] ; i <= R[k]; i++)    ma[k] = ma[k] > a[i]? ma[k]:a[i];
    }
    
    inline void update(int l,int r)
    {
        if( id[ l ] == id[ r ] ){
            if( ma[ id[l] ] <= 1 )  return ;
    
            update_sum(l,r,id[l]);
            update_max(id[l]);
    
            return ;
        }
    
        if( ma[ id[l] ] > 1 )
            update_sum( l,R[id[l]],id[l] ),update_max( id[l] );
    
        if( ma[ id[r] ] > 1 )
            update_sum( L[ id[r] ] , r, id[r] ), update_max( id[r] );
    
        for(int i = id[l] + 1 ; i < id[r] ; i++ ){
            if( ma[ i ] > 1 ) update_sum( L[i],R[i],i ),ma[i] = sqrt(ma[i]);
        }
    
    }
    
    int query(int l,int r)
    {
        int res = 0;
        if( id[l] == id[r] ){
            for(int i = l ; i <= r; i ++)   res += a[i];
            return res;
        }
    
        for(int i = l ; i <= R[ id[l] ] ; i ++) res += a[i];
        for(int i = L[ id[r] ] ; i <= r;  i ++) res += a[i];
    
        for(int i = id[ l ] + 1 ; i < id[r] ; i++)  res += sum[i];
    
        return res;
    }
    
    
    int main()
    {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
        cout.tie(nullptr);
    
        int n;
        cin >> n ;
        len = sqrt(n);
        for(int i = 1; i <= n ; i++){
            cin >> a[i];
            id[i] = ( i - 1 ) / len + 1;
            sum[ id[i] ] += a[i];
            ma[ id[i] ] = ma[ id[i] ] > a[i] ? ma[ id[i] ] : a[i];
        }
    
        for(int i = 1 ; i <= id[n] ; i++){
            L[i] = (i-1)*len+1 , R[i] = min( i*len , n );
        }
    
        for(int i = 0; i < n ; i++){
            int op,x,y,z;
            cin >> op >> x >> y >>z;
            if( op == 0 ){
                update( x,y );
            } else {
                cout << query( x,y ) <<endl;
            }
        }
    
    
    
        return 0;
    }
    
    
  • 相关阅读:
    高性能网站建设之 MS Sql Server数据库分区
    Sql Server 分区演练
    数据库的优化措施 索引优化
    TabHost两种不同的实现方式
    Call requires API level 7 (current min is 1):(问题解决)
    Android特效 五种Toast详解
    SQLite使用
    android下db-journal文件作用
    关于android通过shell修改文件权限的学习
    关于android写入SD卡数据的学习代码
  • 原文地址:https://www.cnblogs.com/hoppz/p/15400617.html
Copyright © 2011-2022 走看看