2017-2018 ACM-ICPC Latin American Regional Programming Contest D - Daunting device【分块】

题意:每次操作将区间颜色置为x,要求可以查询某个颜色出现次数,强制在线,求最后出现次数最多的颜色的次数。

分析:考虑分块做法。

对于每个块记录一个laz,laz为0表示这个块中的颜色不唯一,否则表示该颜色。

更新时两端暴力更新,若整块的laz不为0,直接O(1)得到,否则暴力更新。

分析一下复杂度,两端暴力更新O(n^1/2),laz不为0的块O(1),laz为0的块O(n^1/2)。

同时每次更新仅仅会产生2个laz为0的块,当laz为0的块经过一次暴力更新后,laz必然不为0,所以总共暴力更新整块的次数不会超过2n次。所以复杂度O(n*sqrt(n))。

#include <bits/stdc++.h>

using namespace std;
const int mod = 1e9 + 7;
int mat, num;
int a[100004];
int L[350], R[350];
int col[100004];
int laz[350];

void upd(int l, int r, int x) {
    int st = l / mat + 1;
    int ed = r / mat + 1;
    if(st == ed){
        if(laz[st])
            for (int i = L[st]; i <= R[st]; ++i) {
                a[i] = laz[st];
            }
        laz[st]=0;
        for (int i = l; i <= r; ++i) {
            col[a[i]]--;
            col[x]++;
            a[i]=x;
        }
        return;
    }
    st ++;
    ed --;
    for (int i = st; i <= ed; ++i) {
        if (laz[i]) {
            col[laz[i]] -= R[i] - L[i] + 1;
            col[x] += R[i] - L[i] + 1;
            laz[i] = x;
        } else {
            for (int j = L[i]; j <= R[i]; ++j) {
                col[a[j]]--;
                col[x]++;
                a[j] = x;
            }
            laz[i] = x;
        }
    }
    if (laz[st - 1])
        for (int i = L[st - 1]; i <= R[st - 1]; ++i) {
            a[i] = laz[st - 1];
        }
    laz[st - 1] = 0;
    if (laz[ed + 1])
        for (int i = L[ed + 1]; i <= R[ed + 1]; ++i) {
            a[i] = laz[ed + 1];
        }
    laz[ed + 1] = 0;
    for (int i = l; i < L[st]; ++i) {
        col[a[i]]--;
        col[x]++;
        a[i] = x;
    }
    for (int i = R[ed]+1; i <= r; ++i) {
        col[a[i]]--;
        col[x]++;
        a[i] = x;
    }
}

int main() {
    int l, c, n;
    memset(col, 0, sizeof(col));
    scanf("%d%d%d", &l, &c, &n);
    mat = sqrt(l);
    num = (l + mat - 1) / mat;
    for (int i = 1; i <= num; ++i) {
        laz[i] = 1;
        L[i] = (i - 1) * mat;
        R[i] = i * mat - 1;
    }
    for (int i = 0; i < l; ++i) {
        a[i] = 1;
    }
    R[num] = l - 1;
    col[1] = l;
    for (int i = 0; i < n; ++i) {
        long long p, x, a, b;
        scanf("%lld%lld%lld%lld", &p, &x, &a, &b);
        long long s = col[p];
        long long m1 = (a + s * s % l) % l;
        long long m2 = (a + (s + b) * (s + b) % l) % l;
        if (m1 > m2)swap(m1, m2);
        upd(m1, m2, x);
    }
    int ans = 0;
    for (int i = 1; i <= c; ++i) {
        ans = max(ans,col[i]);
    }
    cout<<ans<<endl;
}

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值