莫队/分块

莫队:O()

算法:算法核心是分块与排序。分块是将数组分成大小为的几块,然后对左端点所在块的编号进行排序,如果相等则按照右端点进行排序。
#include <bits/stdc++.h>
#include <iostream>
#include <cstdio>
#define ll long long
#define inf 0x3f3f3f3f
const int mod = 1e9+7;
const int msize = 50005;
using namespace std;

ll cnt[msize],ans[msize],sum;
int a[msize],l,r,m,n,k,block;
struct node{
    int l,r,xb;
    friend bool operator < (node a,node b){
        if(a.l / block == b.l / block) return a.r < b.r;
        return a.l / block < b.l / block;
    }
}q[50005];

void add(int t)
{
    ll temp = cnt[a[t]];
    cnt[a[t]]++;
    sum += cnt[a[t]] * cnt[a[t]] - temp * temp;
}

void del(int t)
{
    ll temp = cnt[a[t]];
    cnt[a[t]]--;
    sum += cnt[a[t]] * cnt[a[t]] - temp * temp;
}

int main()
{
    scanf("%d%d%d",&n,&m,&k);
    block = sqrt(n);
    sum = 0;
    for(int i = 1; i <= n; i++) scanf("%d",&a[i]);
    for(int i = 1; i <= m; i++){
        scanf("%d%d",&q[i].l,&q[i].r);
        q[i].xb = i;
    }
    l = 1,r = 0;
    sort(q + 1,q + m + 1);
    for(int i = 1; i <= m; i++){
        while(l < q[i].l) del(l++);
        while(l > q[i].l) add(--l);
        while(r < q[i].r) add(++r);
        while(r > q[i].r) del(r--);
        ans[q[i].xb] = sum;
    }
    for(int i = 1; i <= m; i++){
        printf("%lld\n",ans[i]);
    }
    return 0;
}

分块

用来解决用线段树和树状数组难以实现的题。
算法实现:
一:建立块
1)将数组分成大小为的几块,算出每一块的左端点的下标l[i]与右端点下标r[i]
2)算出每个下标所属块存在数组belong中。
二:区间加法  [L,R]
1)利用belong数组找到L,R所属块bl,br。
2)如果相等说明这个区间在同一块里面,那我们直接对区间[L,R]里面的每个数加上c
3)如果不等,那我们对区间[L,r[bl]],[l[br,R]里面的每个数加上c,然后对(bl,br)的每个块进行整体加c,即add[i] += c。
三:单点查值 r
直接查找a[r] + add[belong[r]]即可.


#include <bits/stdc++.h>
#include <iostream>
#include <cstdio>
#define LL long long
#define inf 0x3f3f3f3f
const int mod = 1e9+7;
const int msize = 50005;
using namespace std;

int a[msize],belong[msize],l[msize],r[msize],add[msize],n;
void build()
{
    int block = sqrt(n);
    int m = n / block;
    if(n % block) m++;
    for(int i = 1; i <= m; i++) l[i] = (i - 1) * block + 1,r[i] = i * block;
    r[m] = n;
    for(int i = 1; i <= n; i++){
        belong[i] = (i - 1) / block + 1;
    }
}

void Add(int L,int R,int c)
{
    int bl,br;
    bl = belong[L];
    br = belong[R];
    if(bl == br){
        for(int i = L; i <= R; i++){
            a[i] += c;
        }
        return;
    }
    for(int i = L; i <= r[bl]; i++) a[i] += c;
    for(int i = l[br]; i <= R; i++) a[i] += c;
    for(int i = bl+1; i < br; i++) add[i] += c;
}

int main()
{
	int opt,l,r,c;
	cin >> n;
	for(int i = 1; i <= n; i++) cin >> a[i];
    build();
    for(int i = 1; i <= n; i++){
        cin >> opt >> l >> r >> c;
        if(opt == 1){
            cout << a[r] + add[belong[r]] << endl;
        }
        else{
            Add(l,r,c);
        }
    }
	return 0;
}



全部评论

相关推荐

10-05 11:11
海南大学 Java
投票
理想江南137:感觉挺真诚的 感觉可以试一试
点赞 评论 收藏
分享
吃不饱的肱二头肌很想退休:tnnd 我以为选妹子呢,亏我兴高采烈的冲进来😠
投递快手等公司10个岗位
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务