• GSS4


    GSS4 - Can you answer these queries IV || luogu4145上帝造题的七分钟2 / 花神游历各国

    GSS4 - Can you answer these queries IV

    题目链接:https://www.luogu.org/problemnew/show/SP2713
    线段树经典题目,然而被我用分块A了.
    对于区间开根号,(1e18)最多会被开(6)次就会成为(1),成为(1)后,再开根号也是(1),0开根号也是0,线段树(分块)维护区间所有的数是否全部小于等于1,如果不是,就暴力更新,如果是,那就不要更新这个区间.
    时间复杂度(O(sqrt n * n))
    分块CODE:

    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <cmath>
    #define ll long long
    const int maxN = 100000 + 7;
    ll a[maxN];
    bool is_sqrt[maxN];
    int L[maxN],R[maxN],belong[maxN];
    ll sum[maxN];
    int num[maxN];
    
    inline ll read() {
        ll x = 0,f = 1;char c = getchar();
        while(c < '0' || c > '9') {if(c == '-')f = -1;c = getchar();}
        while(c >= '0' && c <= '9') {x = x * 10 + c - '0';c = getchar();}
        return x * f;
    }
    
    ll Query(int l,int r) {
        int b_l = belong[l],b_r = belong[r];
        ll ans = 0;
        if(b_l == b_r) {
            for(int i = l;i <= r;++ i) 
                ans += a[i];
            return ans;
        }
        for(int i = b_l + 1;i < b_r;++ i) ans += sum[i];
        for(int i = l;i <= R[b_l];++ i) ans += a[i];
        for(int i = L[b_r];i <= r;++ i) ans += a[i];
        return ans;
    }
    
    void Inter_sqrt(int l,int r) {
        int b_l = belong[l],b_r = belong[r];
        if(b_l == b_r) {
            if(is_sqrt[b_l]) return; 
            for(int i = l;i <= r;++ i) {
                if(a[i] == 1) continue;
                sum[b_l] -=a[i];
                a[i] = sqrt(a[i]);
                sum[b_l] += a[i];
                if(a[i] == 1) num[b_l] ++;
            }
            if(num[b_l] == R[b_l] - L[b_l] + 1) is_sqrt[b_l] = true;
            return;
        }
        for(int i = b_l + 1;i < b_r;++ i) {
            if(is_sqrt[i]) continue;
            for(int j = L[i];j <= R[i];++ j) {
                if(a[j] == 1) continue;
                sum[i] -=a[j];
                a[j] = sqrt(a[j]);
                sum[i] += a[j];
                if(a[j] == 1) num[i] ++;
            }
            if(num[i] == R[i] - L[i] + 1) is_sqrt[i] = true;
        }
        for(int i = l;i <= R[b_l];++ i) {
            if(a[i] == 1) continue;
            sum[b_l] -=a[i];
            a[i] = sqrt(a[i]);
            sum[b_l] += a[i];
            if(a[i] == 1) num[b_l] ++;
        }
        if(num[b_l] == R[b_l] - L[b_l] + 1) is_sqrt[b_l] = true;
    
        for(int i = L[b_r];i <= r;++ i) {
            if(a[i] == 1) continue;
            sum[b_r] -=a[i];
            a[i] = sqrt(a[i]);
            sum[b_r] += a[i];
            if(a[i] == 1) num[b_r] ++;
        }
        if(num[b_r] == R[b_r] - L[b_r] + 1) is_sqrt[b_r] = true;
    }
    
    int main() {
        int tot = 0;
        int n;
        while(scanf("%d",&n) == 1) {
            printf("Case #%d:
    ",++ tot);
            memset(num,0,sizeof(num));
            memset(L,0,sizeof(L));
            memset(R,0,sizeof(R));
            memset(sum,0,sizeof(sum));
            memset(is_sqrt,0,sizeof(is_sqrt));
            int q = sqrt(n);
            for(int i = 1;i <= n;++ i) 
                a[i] = read();
            for(int i = 1;i <= n;++ i){
                belong[i] = i / q + 1;
                sum[belong[i]] += a[i];
                if(a[i] == 1) num[belong[i]] ++;
            }
            for(int i = 1;i <= n;++ i) R[belong[i]] = i; 
            for(int i = n;i >= 1;-- i) L[belong[i]] = i;
            int m = read();
            int opt,l,r;
            while(m --) {
                opt = read();l = read();r = read();
                if(l > r) std::swap(l,r); 
                if(opt) printf("%lld
    ",Query(l,r));
                else Inter_sqrt(l,r);
            } 	
        }
        return 0;
    }
    

    luogu4145上帝造题的七分钟2 / 花神游历各国

    用分块很难水过,我们用线段树维护区间最大值即可.
    线段树CODE:

    #include <algorithm>
    #include <iostream>
    #include <cstdio>
    #include <cmath>
    #define max(a,b) a > b ? a : b
    #define ll long long
    const ll maxN = 100000 + 7;
    using namespace std;
    
    struct Node{
        ll l,r;
        ll sum;
        ll maxx;
    }tree[maxN << 2];
    ll a[maxN];
    
    void swap(ll &a,ll &b) {
        ll k = b;
        b = a;
        a = k;
    }
    
    inline ll read() {
        ll x = 0,f = 1;char c = getchar();
        while(c < '0' || c > '9') {if(c == '-')f = -1;c = getchar();}
        while(c >= '0' && c <= '9') {x = x * 10 + c - '0';c = getchar();}
        return x * f;
    }
    
    void updata(ll now) {
        tree[now].sum = tree[now << 1].sum + tree[now << 1 | 1].sum;
        tree[now].maxx = max(tree[now << 1 | 1].maxx,tree[now << 1].maxx);
    }
    
    void build(ll l,ll r,ll now) {
        tree[now].l = l;
        tree[now].r = r;
        if(l == r) {
            tree[now].sum = a[l];
            tree[now].maxx = a[l];
            return ;
        }
        ll mid = (l + r) >> 1;
        build(l,mid,now << 1);
        build(mid + 1,r,now << 1 | 1);
        updata(now);
    }
    
    ll Query(ll l,ll r,ll now) {
        if(tree[now].l >= l && tree[now].r <= r) return tree[now].sum;
        ll mid = (tree[now].l + tree[now].r) >> 1;
        ll sum = 0;
        if(l <= mid) sum += Query(l,r,now << 1);
        if(r > mid) sum += Query(l,r,now << 1 | 1);
        return sum;
    }
    
    void work(ll now) {
        if(tree[now].l == tree[now].r) {
            ll L = tree[now].l;
            a[L] = sqrt(a[L]);
            tree[now].sum = a[L];
            tree[now].maxx = a[L];
            return;
        }
        if(tree[now << 1].maxx > 1) work(now << 1);
        if(tree[now << 1 | 1].maxx > 1) work(now << 1 | 1);
        updata(now);
        return ;
    }
    
    void Inter_sqrt(ll l,ll r,ll now) {
        if(tree[now].l >= l && tree[now].r <= r) {
            if( tree[now].maxx > 1 ) work(now);
            return ;
        }
        ll mid = (tree[now].l + tree[now].r) >> 1;
        if(l <= mid) Inter_sqrt(l,r,now << 1);	
        if(r > mid) Inter_sqrt(l,r,now << 1 | 1);
        updata(now);
        return;
    }
    
    int main() {
        ll n = read();
        for(ll i = 1;i <= n;++ i) 
            a[i] = read();
        build(1,n,1);
        ll m = read();
        ll opt,l,r;
        while(m --) {
            opt = read();l = read();r = read();
            if(l > r)swap(l,r);
            if(opt == 1) printf("%lld
    ",Query(l,r,1));
            else Inter_sqrt(l,r,1);
        }
        return 0;
    }
    
    /*
    10
    1 2 3 4 5 6 7 8 9 10
    5
    0 1 10
    1 1 10
    1 1 5
    0 5 8
    1 4 8
    */
    
  • 相关阅读:
    [GXOI/GZOI2019] 旧词
    [HDU6756] Finding a MEX
    [洛谷P5110] 块速递推
    [CF739C] Alyona and towers
    1349. 修理牛棚
    L2-028 秀恩爱分得快 (25 分)
    L2-009 抢红包 (25 分)
    L1-043 阅览室 (20 分)
    2020年天梯赛-模拟赛 L1-6 检查密码 (15 分)
    L1-046 整除光棍 (20 分)
  • 原文地址:https://www.cnblogs.com/tpgzy/p/9734015.html
Copyright © 2020-2023  润新知