数列分块入门1~9 loj6277~6285

hzwer的讲解

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

#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
int n, a[50005], opt, uu, vv, ww, tag[305], blc, bel[50005];
void add(int uu, int vv, int ww){
    int p=bel[uu], q=bel[vv];
    if(p==q)
        for(int i=uu; i<=vv; i++)
            a[i] += ww;
    else{
        for(int i=p+1; i<=q-1; i++) tag[i] += ww;
        for(int i=uu; i<=bel[uu]*blc; i++)  a[i] += ww;
        for(int i=(bel[vv]-1)*blc+1; i<=vv; i++)    a[i] += ww;
    }
}
int main(){
    cin>>n;
    blc = sqrt(n);
    for(int i=1; i<=n; i++) scanf("%d", &a[i]);
    for(int i=1; i<=n; i++) bel[i] = (i - 1) / blc + 1;
    for(int i=1; i<=n; i++){
        scanf("%d %d %d %d", &opt, &uu, &vv, &ww);
        if(!opt)    add(uu, vv, ww);
        else    printf("%d\n", a[vv]+tag[bel[vv]]);
    }
    return 0;
}

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

#include <algorithm>
#include <iostream>
#include <cstdio>
#include <vector>
#include <cmath>
using namespace std;
int n, blc, a[50005], tag[50005], bel[50005], opt, uu, vv, ww;
vector<int> vec[50005];
void qwq(int tat){
    vec[tat].clear();
    for(int i=(tat-1)*blc+1; i<=min(tat*blc, n); i++)   vec[tat].push_back(a[i]);
    sort(vec[tat].begin(), vec[tat].end());
}
void update(int uu, int vv, int ww){
    if(bel[uu]==bel[vv]){
        for(int i=uu; i<=vv; i++)   a[i] += ww;
        qwq(bel[uu]);
    }
    else{
        for(int i=bel[uu]+1; i<=bel[vv]-1; i++) tag[i] += ww;
        for(int i=uu; i<=bel[uu]*blc; i++)  a[i] += ww;
        for(int i=(bel[vv]-1)*blc+1; i<=vv; i++)    a[i] += ww;
        qwq(bel[uu]); qwq(bel[vv]);
    }
}
int query(int uu, int vv, int ww){
    int re=0;
    if(bel[uu]==bel[vv]){
        for(int i=uu; i<=vv; i++)
            if(a[i]+tag[bel[i]]<ww)
                re++;
    }
    else{
        for(int i=bel[uu]+1; i<=bel[vv]-1; i++)
            re += lower_bound(vec[i].begin(), vec[i].end(), ww-tag[i]) - vec[i].begin();
        for(int i=uu; i<=bel[uu]*blc; i++)
            if(a[i]+tag[bel[i]]<ww)
                re++;
        for(int i=(bel[vv]-1)*blc+1; i<=vv; i++)
            if(a[i]+tag[bel[i]]<ww)
                re++;
    }
    return re;
}
int main(){
    cin>>n;
    blc = sqrt(n/200);
    for(int i=1; i<=n; i++){
        bel[i] = (i - 1) / blc + 1;
        scanf("%d", &a[i]);
        vec[bel[i]].push_back(a[i]);
    }
    for(int i=1; i<=n; i=bel[i]*blc+1)
        sort(vec[bel[i]].begin(), vec[bel[i]].end());
    for(int i=1; i<=n; i++){
        scanf("%d %d %d %d", &opt, &uu, &vv, &ww);
        if(!opt)    update(uu, vv, ww);
        else    printf("%d\n", query(uu, vv, ww*ww));
    }
    return 0;
}

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

#include <algorithm>
#include <iostream>
#include <cstdio>
#include <vector>
#include <cmath>
using namespace std;
int n, blc, a[100005], bel[100005], tag[100005], opt, uu, vv, ww;
vector<int> vec[100005];
void qwq(int u){
    vec[u].clear();
    for(int i=(u-1)*blc+1; i<=min(n, blc*u); i++)
        vec[u].push_back(a[i]);
    sort(vec[u].begin(), vec[u].end());
}
void update(int uu, int vv, int ww){
    if(bel[uu]==bel[vv]){
        for(int i=uu; i<=vv; i++)
            a[i] += ww;
        qwq(bel[uu]);
    }
    else{
        for(int i=bel[uu]+1; i<=bel[vv]-1; i++) tag[i] += ww;
        for(int i=uu; i<=bel[uu]*blc; i++)  a[i] += ww;
        for(int i=(bel[vv]-1)*blc+1; i<=vv; i++)    a[i] += ww;
        qwq(bel[uu]); qwq(bel[vv]);
    }
}
int query(int uu, int vv, int ww){
    int re=0xffffffff;
    if(bel[uu]==bel[vv]){
        for(int i=uu; i<=vv; i++)
            if(a[i]+tag[bel[i]]<ww)
                re = max(re, a[i]+tag[bel[i]]);
    }
    else{
        for(int i=bel[uu]+1; i<=bel[vv]-1; i++){
            int pos=lower_bound(vec[i].begin(), vec[i].end(), ww-tag[i])-vec[i].begin();
            if(pos) re = max(re, vec[i][pos-1]+tag[i]);
        }
        for(int i=uu; i<=bel[uu]*blc; i++)
            if(a[i]+tag[bel[i]]<ww)
                re = max(re, a[i]+tag[bel[i]]);
        for(int i=(bel[vv]-1)*blc+1; i<=vv; i++)
            if(a[i]+tag[bel[i]]<ww)
                re = max(re, a[i]+tag[bel[i]]);
    }
    if(re==0xffffffff)  return -1;
    else    return re;
}
int main(){
    cin>>n;
    blc = sqrt(n*log(n)/log(2));
    for(int i=1; i<=n; i++){
        scanf("%d", &a[i]);
        bel[i] = (i - 1) / blc + 1;
        vec[bel[i]].push_back(a[i]);
    }
    for(int i=1; i<=n; i=bel[i]*blc+1)
        sort(vec[bel[i]].begin(), vec[bel[i]].end());
    for(int i=1; i<=n; i++){
        scanf("%d %d %d %d", &opt, &uu, &vv, &ww);
        if(!opt)    update(uu, vv, ww);
        else    printf("%d\n", query(uu, vv, ww));
    }
    return 0;
}

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

poj3468

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

#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
int n, blc, bel[50005], opt, uu, vv, ww, tag[50005], sum[50005], a[50005];
int qwq(int uu, int vv){
    for(int i=uu; i<=vv; i++){
        sum[bel[i]] -= a[i];
        a[i] = sqrt(a[i]);
        sum[bel[i]] += a[i];
    }
    return sum[bel[uu]];
}
void qaq(int u){
    if(tag[u])  return ;
    int re=qwq((u-1)*blc+1, u*blc);
    if(re>blc)  tag[u] = false;
    else    tag[u] = true;
}
void update(int uu, int vv){
    if(bel[uu]==bel[vv])
        qwq(uu, vv);
    else{
        for(int i=bel[uu]+1; i<=bel[vv]-1; i++) qaq(i);
        qwq(uu, bel[uu]*blc);
        qwq((bel[vv]-1)*blc+1, vv);
    }
}
int query(int uu, int vv){
    int re=0;
    if(bel[uu]==bel[vv])
        for(int i=uu; i<=vv; i++)
            re += a[i];
    else{
        for(int i=bel[uu]+1; i<=bel[vv]-1; i++) re += sum[i];
        for(int i=uu; i<=bel[uu]*blc; i++)  re += a[i];
        for(int i=(bel[vv]-1)*blc+1; i<=vv; i++)    re += a[i];
    }
    return re;
}
int main(){
    cin>>n;
    blc = sqrt(n);
    for(int i=1; i<=n; i++){
        scanf("%d", &a[i]);
        bel[i] = (i - 1) / blc + 1;
        sum[bel[i]] += a[i];
    }
    for(int i=1; i<=n; i++){
        scanf("%d %d %d %d", &opt, &uu, &vv, &ww);
        if(!opt)    update(uu, vv);
        else    printf("%d\n", query(uu, vv));
    }
    return 0;
}

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

#include <algorithm>
#include <iostream>
#include <cstdio>
#include <vector>
#include <cmath>
using namespace std;
typedef pair<int,int> par;
int n, blc, opt, uu, vv, ww, sta[200005], din, m;
vector<int> vec[200005];
par query(int uu){
    int x=1;
    while(uu>vec[x].size()){
        uu -= vec[x].size();
        x++;
    }
    return make_pair(x, uu-1);
}
void rebuild(){
    din = 0;
    for(int i=1; i<=m; i++){
        for(int j=0; j<vec[i].size(); j++)
            sta[++din] = vec[i][j];
        vec[i].clear();
    }
    blc = sqrt(din);
    for(int i=1; i<=din; i++)
        vec[(i-1)/blc+1].push_back(sta[i]);
}
void update(int uu, int vv){
    par re=query(uu);
    vec[re.first].insert(vec[re.first].begin()+re.second, vv);
    if(vec[re.first].size()>blc+blc)    rebuild();
}
int main(){
    cin>>n;
    blc = sqrt(n);
    m = (n - 1) / blc + 1;
    for(int i=1; i<=n; i++){
        scanf("%d", &uu);
        vec[(i-1)/blc+1].push_back(uu);
    }
    for(int i=1; i<=n; i++){
        scanf("%d %d %d %d", &opt, &uu, &vv, &ww);
        if(!opt)    update(uu, vv);
        else{
            par re=query(vv);
            printf("%d\n", vec[re.first][re.second]);
        }
    }
    return 0;
}

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

#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
int n, a[100005], bel[100005], add[100005], mul[100005], blc;
int opt, uu, vv, ww;
const int mod=10007;
void pushDown(int x){
    for(int i=(x-1)*blc+1; i<=min(n, x*blc); i++)
        a[i] = (a[i] * mul[x] + add[x]) % mod;
    mul[x] = 1; add[x] = 0;
}
void updAdd(int uu, int vv, int ww){
    pushDown(bel[uu]);
    if(bel[uu]==bel[vv])
        for(int i=uu; i<=vv; i++)
            a[i] = (a[i] + ww) % mod;
    else{
        pushDown(bel[vv]);
        for(int i=bel[uu]+1; i<=bel[vv]-1; i++) add[i] = (add[i] + ww) % mod;
        for(int i=uu; i<=bel[uu]*blc; i++)  a[i] = (a[i] + ww) % mod;
        for(int i=(bel[vv]-1)*blc+1; i<=vv; i++)    a[i] = (a[i] + ww) % mod;
    }   
}
void updMul(int uu, int vv, int ww){
    pushDown(bel[uu]);
    if(bel[uu]==bel[vv])
        for(int i=uu; i<=vv; i++)
            a[i] = (a[i] * ww) % mod;
    else{
        pushDown(bel[vv]);
        for(int i=bel[uu]+1; i<=bel[vv]-1; i++){
            mul[i] = (mul[i] * ww) % mod;
            add[i] = (add[i] * ww) % mod;
        }
        for(int i=uu; i<=bel[uu]*blc; i++)  a[i] = (a[i] * ww) % mod;
        for(int i=(bel[vv]-1)*blc+1; i<=vv; i++)    a[i] = (a[i] * ww) % mod;
    }   
}
int main(){
    cin>>n;
    blc = sqrt(n);
    for(int i=1; i<=n; i++){
        mul[i] = 1;
        scanf("%d", &a[i]);
        bel[i] = (i - 1) / blc + 1;
    }
    for(int i=1; i<=n; i++){
        scanf("%d %d %d %d", &opt, &uu, &vv, &ww);
        if(!opt)    updAdd(uu, vv, ww);
        else if(opt==1) updMul(uu, vv, ww);
        else    printf("%d\n", (a[vv]*mul[bel[vv]]+add[bel[vv]])%mod);
    }
    return 0;
}

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

#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
int n, a[100005], tag[100005], bel[100005], blc, uu, vv, ww;
void pushDown(int x){
    if(tag[x]==-1)  return ;
    for(int i=(x-1)*blc+1; i<=min(n, x*blc); i++)
        a[i] = tag[x];
    tag[x] = -1;
}
int update(int uu, int vv, int ww){
    int re=0;
    if(tag[uu]) pushDown(bel[uu]);
    if(bel[uu]==bel[vv])
        for(int i=uu; i<=vv; i++){
            if(a[i]==ww)
                re++;
            a[i] = ww;
        }
    else{
        if(tag[vv]) pushDown(bel[vv]);
        for(int i=bel[uu]+1; i<=bel[vv]-1; i++){
            if(tag[i]!=-1)
                re += tag[i]==ww?blc:0;
            else
                for(int j=(i-1)*blc+1; j<=i*blc; j++)
                    re += a[j]==ww;
            tag[i] = ww;
        }
        for(int i=uu; i<=bel[uu]*blc; i++){
            re += a[i]==ww;
            a[i] = ww;
        }
        for(int i=(bel[vv]-1)*blc+1; i<=vv; i++){
            re += a[i]==ww;
            a[i] = ww;
        }
    }
    return re;
}
int main(){
    cin>>n;
    blc = sqrt(n);
    for(int i=1; i<=n; i++){
        tag[i] = -1;
        scanf("%d", &a[i]);
        bel[i] = (i - 1) / blc + 1;
    }
    for(int i=1; i<=n; i++){
        scanf("%d %d %d", &uu, &vv, &ww);
        printf("%d\n", update(uu, vv, ww));
    }
    return 0;
}

区间众数
参考luogu4168 蒲公英

转载于:https://www.cnblogs.com/poorpool/p/8463599.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值