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;
    } 
  • 相关阅读:
    通过HttpListener实现简单的Http服务
    WCF心跳判断服务端及客户端是否掉线并实现重连接
    NHibernate初学六之关联多对多关系
    NHibernate初学五之关联一对多关系
    EXTJS 4.2 资料 跨域的问题
    EXTJS 4.2 资料 控件之Grid 那些事
    EXTJS 3.0 资料 控件之 GridPanel属性与方法大全
    EXTJS 3.0 资料 控件之 Toolbar 两行的用法
    EXTJS 3.0 资料 控件之 combo 用法
    EXTJS 4.2 资料 控件之 Store 用法
  • 原文地址:https://www.cnblogs.com/darlingroot/p/10863987.html
Copyright © 2011-2022 走看看