zoukankan      html  css  js  c++  java
  • 分块

    (咕咕咕了好久qwq.)

    hzwer大佬的博客

    分块模板水题

    分块1

    给出一个长为n的数列,以及n个操作,操作涉及区间加法,单点查值。

    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    
    inline int read()
    {
        int sum = 0,p = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9')
        {
            if(ch == '-')
                p = -1;
            ch = getchar();
        }
        while(ch >= '0' && ch <= '9')
        {
            (sum *= 10) += ch - '0';
            ch = getchar();
        }
        return sum * p;
    }
    
    const int maxn = 50005;
    int n,blo;
    int v[maxn],block[maxn],atag[maxn];
    
    void add(int a,int b,int c)
    {
        for(int i = a;i <= min(block[a] * blo,b);i++)
            v[i] += c;
        if(block[a] != block[b])
            for(int i = (block[b] - 1)* blo + 1;i <= b;i++)
                v[i] += c;
        for(int i = block[a] + 1;i <= block[b] - 1;i++)
            atag[i] += c; 
    }
    
    int main()
    {
        n = read();
        blo = sqrt(n);
        for(int i = 1;i <= n;i++)
            v[i] = read();
        for(int i = 1;i <= n;i++)
            block[i] = (i - 1)/blo + 1;
        for(int i = 1;i <= n;i++)
        {
            int opt = read(),a = read(),b = read(),c = read();
            if(opt == 0)
                add(a,b,c);
            if(opt == 1)
                printf("%d
    ",v[b] + atag[block[b]]);
        }
        return 0;
    }

    分块2
    给出一个长为n的数列,以及n个操作,操作涉及区间加法,询问区间内小于某个值x的元素个数。

    //区间加法,询问区间内小于某个值的元素个数
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<vector>
    #include<iostream>
    using namespace std;
    
    inline int  read()//快读 
    {
        int sum = 0,p = 1;
        char ch = getchar();
        while(ch < '0'|| ch > '9')
        {
            if(ch == '-')
                p = -1;
            ch = getchar();
        }
        while(ch >= '0' && ch <= '9')
        {
            (sum *= 10) += ch - '0';
            ch = getchar();
        }
        return sum * p;
    }
    
    const int maxn = 50005;
    int n,blo; 
    int v[maxn],block[maxn],atag[maxn];
    vector<int>ve[505];
    
    void reset(int x)
    {
        ve[x].clear();
        for(int i = (x - 1) *blo + 1;i <= min(x * blo , n);i++)
            ve[x].push_back(v[i]);
        sort(ve[x].begin(),ve[x].end());
    }
    
    void add(int a,int b,int c)
    {
        for(int i = a;i <= min(block[a] *blo,b);i++)
            v[i] += c;
        reset(block[a]);
        if(block[a] != block[b])
        {
            for(int i = (block[b] - 1)* blo + 1;i <= b;i++)
                v[i] += c;
            reset(block[b]);
        }
        for(int i = block[a] + 1;i <= block[b] - 1;i++)
            atag[i] += c;
    }
    
    int query(int a,int b,int c)
    {
        int ans = 0;
        for(int i = a;i <= min(block[a] * blo , b);i++)
            if(v[i] + atag[block[i]]< c)
                ans++;
        if(block[a] != block[b])
            for(int i = (block[b] - 1) * blo + 1;i <= b;i++)
                if(v[i] +atag[block[i]] < c)
                    ans++;
        for(int i = block[a] + 1;i <= block[b] - 1;i++)            
        {
            int x = c - atag[i];
            ans += lower_bound(ve[i].begin(),ve[i].end(),x) - ve[i].begin();
        }
        return ans;
    }
    
    int main()
    {
        n = read();
        blo = sqrt(n);
        for(int i = 1;i <= n;i++)
            v[i] = read();
        for(int i = 1;i <= n;i++)
        {
            block[i] = (i - 1) / blo + 1;
            ve[block[i]].push_back(v[i]);
        }
        for(int i = 1;i <= block[n];i++)
            sort(ve[i].begin(),ve[i].end());
        for(int i = 1;i <= n;i++)
        {
            int opt = read(),a = read(),b = read(),c = read();
            if(opt == 0)
                add(a,b,c);
            if(opt == 1)
                printf("%d
    ",query(a,b,c * c));
        }
        return 0;
    } 

    分块3

    给出一个长为n 的数列,以及n 个操作,操作涉及区间加法,询问区间内小于某个值x 的前驱(比其小的最大元素)。

    //区间加法,询问区间内小于某个值x的前驱(比其小的最大前驱)
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<set>
    using namespace std;
    
    inline int read()//快读
    {
        int sum = 0,p = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9')
        {
            if(ch == '-')
                p = -1;
            ch = getchar();
        }
        while(ch >= '0' && ch <= '9')
        {
            (sum *= 10) += ch - '0';
            ch = getchar();
        }
        return sum * p;
    }
    
    const int maxn = 100005;
    int n,blo;
    int v[maxn],block[maxn],atag[maxn];
    set<int>st[105];
    
    void add(int a,int b,int c)
    {
        for(int i = a;i <= min(block[a] * blo , b);i++)
        {
            st[block[a]].erase(v[i]);
            v[i] += c;
            st[block[a]].insert(v[i]);
        }
        if(block[a] != block[b])
            for(int i = (block[b] - 1) * blo + 1;i <= b;i++)
            {
                st[block[b]].erase(v[i]);
                v[i] += c;
                st[block[b]].insert(v[i]);
            }
        for(int i = block[a] + 1;i <= block[b] - 1;i++)
            atag[i] += c;
    }
    int query(int a,int b,int c)
    {
        int ans = -1;
        for(int i = a;i <= min(block[a] * blo , b);i++)
        {
            int cnt = v[i] + atag[block[a]];
            if(cnt < c)
                ans = max(ans,cnt);
        }
        if(block[a] != block[b])
            for(int i = (block[b] - 1) * blo + 1;i <= b;i++)
            {
                int cnt = v[i] + atag[block[b]];
                if(cnt < c)
                    ans = max(ans,cnt);
            }
        for(int i = block[a] + 1;i <= block[b] - 1;i++)
        {
            int cnt = c - atag[i];
            set<int>::iterator it = st[i].lower_bound(cnt);
            if(it == st[i].begin())
                continue;
            --it;
            ans = max(ans,*it + atag[i]);
        }
        return ans;
    }
    
    int main()
    {
        n = read();
        blo = 1000;
        for(int i = 1;i <= n;i++)
            v[i] = read();
        for(int i = 1;i <= n;i++)
        {
            block[i] = (i - 1)/blo + 1;
            st[block[i]].insert(v[i]);
        }
        for(int i = 1;i <= n;i++)
        {
            int opt = read(),a = read(),b = read(),c = read();
            if(opt == 0)
                add(a,b,c);
            if(opt == 1)
                printf("%d
    ",query(a,b,c));
        }
        return 0;
    }

    分块4

    给出一个长为n 的数列,以及n 个操作,操作涉及区间加法,区间求和。

    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #define ll long long
    using namespace std;
    
    inline ll read()
    {
        int sum = 0,p = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9')
        {
            if(ch == '-')
                p = -1;
            ch = getchar();
        }
        while(ch >= '0' && ch <= '9')
        {
            (sum *= 10) += ch - '0';
            ch = getchar();
        }
        return sum * p;
    }
    
    const int maxn = 50005;
    int n,blo;
    ll v[maxn];
    ll block[maxn],atag[maxn],sum[maxn];
    
    void add(ll a,ll b,ll c)
    {
        for(int i = a;i <= min(block[a] * blo,b);i++)
        {
            v[i] += c;
            sum[block[a]] += c;
        }
        if(block[a] != block[b])
            for(int i = (block[b] - 1) * blo + 1;i <= b;i++)
            {
                v[i] += c;
                sum[block[b]] += c;
            }
        for(int i = block[a] + 1;i <= block[b] - 1;i++)
            atag[i] += c;
    }
    
    void query(ll a,ll b,ll c)
    {
        ll ans = 0;
        for(int i = a;i <= min(block[a] * blo,b);i++)
            ans = (ans + v[i] % c + atag[block[a]] % c)%c;
        if(block[a] != block[b])
            for(int i = (block[b] - 1) * blo + 1;i <= b;i++)
                ans = (ans + v[i] % c + atag[block[b]] % c)%c;
        for(int i = block[a] + 1;i <= block[b] - 1;i++)
            ans = (ans + sum[i] % c + atag[i] * blo % c)%c;
        printf("%lld
    ",ans);
    }
    
    int main()
    {
        n = read();
        blo = sqrt(n);
        for(int i = 1;i <= n;i++)
            v[i] = read();
        for(int i = 1;i <= n;i++)
        {
            block[i] = (i - 1) / blo + 1;
            sum[block[i]] += v[i];
        }
        for(int i = 1;i <= n;i++)
        {
            ll opt = read(),a = read(),b = read(),c = read();
            if(opt == 0)
                add(a,b,c);
            if(opt == 1)
                query(a,b,c+1);
        }
        return 0;
    }

    分块5

    给出一个长为n 的数列 ,以及n 个操作,操作涉及区间开方,区间求和。

    //区间开方,区间求和
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #define ll long long 
    using namespace std;
    
    inline int read()
    {
        int sum = 0,p = 1;
        char ch = getchar();
        while(ch < '0' | ch > '9')
        {
            if(ch == '-')
                p = -1;
            ch = getchar();
        }
        while(ch >= '0' && ch <= '9')
        {
            (sum *= 10) += ch - '0';
            ch = getchar();
        }
        return sum * p;
    }
    
    const int maxn = 50005;
    ll n,blo;
    ll block[maxn],v[maxn],sum[maxn];
    bool flag[maxn];
    
    void ssqrt(ll x)
    {
        if(flag[x])
            return;
        flag[x] = true;
        sum[x] = 0;
        for(int i = (x - 1) * blo+ 1;i <= x * blo;i++)
        {
            v[i] = sqrt(v[i]);
            sum[x] += v[i];
            if(v[i] > 1)
                flag[x] = false;
        }
    }
    
    void add(ll a,ll b,ll c)
    {
        for(int i = a;i <= min(block[a] * blo,b);i++)
        {
            sum[block[a]] -= v[i];
            v[i] = sqrt(v[i]);
            sum[block[a]] += v[i];
        }
        if(block[a] != block[b])
            for(int i = (block[b] - 1)* blo + 1;i <= b;i++)
            {
                sum[block[b]] -= v[i];
                v[i] = sqrt(v[i]);
                sum[block[b]] += v[i];
            }
        for(int i = block[a] + 1;i <= block[b] - 1;i++)
            ssqrt(i);
    }
    
    void query(ll a,ll b)
    {
        ll ans = 0;
        for(int i = a;i <= min(block[a] * blo,b);i++)
            ans += v[i];
        if(block[a] != block[b])
            for(int i = (block[b] - 1)* blo + 1;i <= b;i++)
                ans += v[i];
        for(int i = block[a] + 1;i <= block[b] - 1;i++)
            ans += sum[i];
        printf("%lld
    ",ans);
    }
    
    int main()
    {
        n = read();
        blo = sqrt(n);
        for(int i = 1;i <= n;i++)
            v[i] = read();
        for(int i = 1;i <= n;i++)
        {
            block[i] = (i - 1) / blo + 1;
            sum[block[i]] += v[i];
        }
        for(int i = 1;i <= n;i++)
        {
            ll opt = read(),a = read(),b = read(),c = read();
            if(opt == 0)
                add(a,b,c);
            else
                query(a,b);
        }
        return 0;
    }

    分块6

    给出一个长为n的数列,以及n个操作,操作涉及单点插入,单点询问,数据随机生成。

    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<vector> 
    #define ll long long
    using namespace std;
    
    inline int read()
    {
        int sum = 0,p = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9')
        {
            if(ch == '-')
                p = -1;
            ch = getchar();
        }
        while(ch >= '0' && ch <= '9')
        {
            (sum *= 10) += ch - '0';
            ch = getchar();
        }
        return sum * p;
    }
    
    int n,m,blo;
    int v[100005];
    vector<int>block[1005];
    int st[200005],top;
    
    pair<int,int> query(int o)
    {
        int x = 1;
        while(o > block[x].size())
        {
            o -= block[x].size();
            x++;
        }
        return make_pair(x,o - 1);
    }
    
    void rebuild()
    {
        top = 0;
        for(int i = 1;i <= m;i++)
        {
            for(vector<int>::iterator j = block[i].begin();j != block[i].end();j++)
                st[++top] = *j;
            block[i].clear();
        }
        int blo2 = sqrt(top);
        for(int i = 1;i <= top;i++)
            block[(i - 1) / blo2 + 1].push_back(st[i]);
        m = (top - 1)/blo2 + 1;
    }
    
    void insert(int a,int b)
    {
        pair<int,int>t = query(a);
        block[t.first].insert(block[t.first].begin() + t.second,b);
        if(block[t.first].size() > 20 * blo)
            rebuild();
    }
    
    int main()
    {
        n = read(),blo = sqrt(n);
        for(int i = 1;i <= n;i++)
            v[i] = read();
        for(int i = 1;i <= n;i++)
            block[(i - 1)/blo + 1].push_back(v[i]);
        m = (n - 1)/blo + 1;
        for(int i = 1;i <= n;i++)
        {
            int opt = read(),a = read(),b = read(),c = read();
            if(opt == 0)
                insert(a,b);
            if(opt == 1)
            {
                pair<int,int>t = query(b);
                printf("%d
    ",block[t.first][t.second]);
            }
        } 
        return 0;
    }

    分块7

    给出一个长为n 的数列,以及n个操作,操作涉及区间乘法,区间加法,单点询问。

    //区间乘法+区间加法+单点查询 
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    
    inline int read()
    {
        int sum = 0,p = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9')
        {
            if(ch == '-')
                p = -1;
            ch = getchar();
        }
        while(ch >= '0' && ch <= '9')
        {
            (sum *= 10) += ch - '0';
            ch = getchar();
        }
        return sum * p;
    }
    
    int n,blo,mod = 10007;
    int v[100005],block[100005],atag[1005],mtag[1005];
    
    void reset(int o)
    {
        for(int i = (o - 1)* blo + 1;i <= min(n,o * blo);i++)
            v[i] = (v[i] * mtag[o] + atag[o])%mod;
        atag[o] = 0;
        mtag[o] = 1;
    }
    
    void solve(int opt,int a,int b,int c)
    {
        reset(block[a]);
        for(int i = a;i <= min(block[a] * blo,b);i++)
        {
            if(opt == 0)
                v[i] += c;
            else
                v[i] *= c;
            v[i] %= mod;
        }
        if(block[a] != block[b])
        {
            reset(block[b]);
            for(int i = (block[b] - 1) * blo + 1;i <= b;i++)
            {
                if(opt == 0)
                    v[i] += c;
                else
                    v[i] *= c;
                v[i] %= mod;
            }
        }
        for(int i = block[a] + 1;i <= block[b] - 1;i++)
        {
            if(opt == 0)
                atag[i] = (atag[i] + c)% mod;
            else
            {
                atag[i] = (atag[i] * c)%mod;
                mtag[i] = (mtag[i] * c)%mod;
            }
        }
    }
    
    int main()
    {
        n = read();
        blo = sqrt(n);
        for(int i = 1;i <= n;i++)
            v[i] = read();
        for(int i = 1;i <= n;i++)
            block[i] = (i - 1)/blo + 1;
        for(int i = 1;i <= block[n];i++)
            mtag[i] = 1;
        for(int i = 1;i <= n;i++)
        {
            int opt = read(),a = read(),b = read(),c = read();
            if(opt == 2)
                printf("%d
    ",(v[b] *mtag[block[b]] +atag[block[b]]) % mod);
            else
                solve(opt,a,b,c);
        }
        return 0;
    } 

    分块8

    给出一个长为n的数列,以及n个操作,操作涉及区间询问等于一个数c的元素,并将这个区间的所有元素改为c

    //区间询问等于一个数c的元素,并将这个区间的所有元素改为c 
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    using namespace std;
    
    inline int read()
    {
        int sum = 0,p = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9')
        {
            if(ch == '-')
                p = -1;
            ch = getchar();
        }
        while(ch >= '0' && ch <= '9')
        {
            (sum *= 10) += ch - '0';
            ch = getchar();
        }
        return sum * p;
    }
    
    int n,blo;
    int v[100005],block[100005],atag[1005];
    
    void reset(int o)
    {
        if(atag[o] == -1)
            return;
        for(int i = (o - 1) * blo + 1;i <= o * blo;i++)
            v[i] = atag[o];
        atag[o] = -1;
    }
    
    void query(int l,int r,int c)
    {
        int ans = 0;
        reset(block[l]);
        for(int i = l;i <= min(blo * block[l],r);i++)
            if(v[i] != c)
                v[i] = c;
            else
                ans++;
        if(block[l] != block[r])
        {
            reset(block[r]);
            for(int i = blo * (block[r] - 1) + 1;i <= r;i++)
                if(v[i] != c)
                    v[i] = c;
                else
                    ans++;
        }
        for(int i = block[l] + 1;i <= block[r] - 1;i++)
        {
            if(atag[i] != -1)
                if(atag[i] != c)
                    atag[i] = c;
                else
                    ans += blo;
            else
            {
                for(int j = blo * (i - 1) + 1;j <= blo * i;j++)
                    if(v[j] != c)
                        v[j] = c;
                    else
                        ans++;
                atag[i] = c;
            }
        }
        printf("%d
    ",ans);
    }
    
    int main()
    {
        n = read();
        blo = sqrt(n);
        memset(atag,-1,sizeof(atag));
        for(int i = 1;i <= n;i++)
            v[i] = read();
        for(int i = 1;i <= n;i++)
            block[i] = (i - 1) / blo + 1;
        for(int i = 1;i <= n;i++)
        {
            int l = read(),r = read(),c = read();
            query(l,r,c);
        }
        return 0;
    } 

    分块9

    给出一个长为n的数列,以及n个操作,操作涉及询问区间的最小众数。

    #include<cstdio>
    #include<algorithm>
    #include<vector>
    #include<map> 
    #include<cstring>
    #define ll long long
    using namespace std;
    
    inline int read()
    {
        int sum = 0,p = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9')
        {
            if(ch == '-')
                p = -1;
            ch = getchar();
        }
        while(ch >= '0' && ch <= '9')
        {
            (sum *= 10) += ch - '0';
            ch = getchar();
        }
        return sum * p;
    }
    
    const int maxn = 100005,maxm = 100005;
    int n,blo = 100,id;
    int v[maxn],block[maxn],val[maxm],cnt[maxn];
    int f[1010][1010];
    map<int,int>mp;
    vector<int>ve[maxn];
    
    void pre(int x)
    {
        memset(cnt,0,sizeof(cnt));
        int mx = 0,ans = 0;
        for(int i = (x - 1) * blo + 1;i <= n;i++)
        {
            int t = block[i];
            cnt[v[i]]++;
            if(cnt[v[i]] > mx || (cnt[v[i]] == mx && val[v[i]] < val[ans]))
            {
                mx = cnt[v[i]];
                ans = v[i];
            }
            f[x][t] = ans;
        } 
    }
    
    int ask(int a,int b,int x)
    {
        return upper_bound(ve[x].begin(),ve[x].end(),b) - lower_bound(ve[x].begin(),ve[x].end(),a);
    }
    
    int query(int a,int b)
    {
        int ans = f[block[a] + 1][block[b] - 1];
        int mx = ask(a,b,ans);
        for(int i = a;i <= min(blo * block[a],b);i++)
        {
            int t = ask(a,b,v[i]);
            if(t > mx || (t == mx && val[v[i]] < val[ans]))
            {
                ans = v[i];
                mx = t; 
            } 
        }
        if(block[a] != block[b])
        {
            for(int i = (block[b] - 1) * blo + 1;i <= b;i++)
            {
                int t = ask(a,b,v[i]);
                if(t > mx || (t == mx && val[v[i]] < val[ans]))
                {
                    ans = v[i];
                    mx = t;
                }
            }
        }
        return ans;
    }
    
    int main()
    {
        n = read();
        for(int i = 1;i <= n;i++)
        {
            v[i] = read();
            if(!mp[v[i]])
            {
                mp[v[i]] = ++id;
                val[id] = v[i];
            }
            v[i] = mp[v[i]];
            ve[v[i]].push_back(i);
        }
        for(int i = 1;i <= n;i++)
            block[i] = (i - 1)/blo + 1;
        for(int i = 1;i <= block[n];i++)
            pre(i);
        for(int i = 1;i <= n;i++)
        {
            int l = read(),r = read();
            if(l > r)
                swap(l,r);
            int t = query(l,r);
            printf("%d
    ",val[t]);
        }
        return 0;
    } 
  • 相关阅读:
    ViewPager+导航条实现方式比较---------来自互联网
    ScrollView重写实现监听
    android:layout_gravity和android:gravity
    解决Android Studio添加依赖时出现“Manifest merger failed
    Android SD卡读取简单操作
    Android文件读取简单操作
    20160623
    Mac 下两款 Markdown 编辑器 Mou/MacDown 大 PK
    iOS开发编码建议与编程经验(书写规范)
    iOS开发调试技巧总结
  • 原文地址:https://www.cnblogs.com/darlingroot/p/10863987.html
Copyright © 2011-2022 走看看