【滚动训练】LOJ6279. 数列分块入门 3 (分块)

题意

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

题解

这道题和数列分块入门2很类似,因为要询问区间小于x的前驱,暴力查找肯定是不行的。自然想到如果区间内是有序的话,就可以在块内二分了。维护有序可以套用上一题的方案,即块内暴力更新的时候sort,或者是使用set自动维护有序。

方案一 块内sort

每次对暴力更新的部分sort即可,查找的时候可以二分查找。

方案二 set维护有序

这个方案是看黄学长的std才学会的,原来set自带二分,但是效率有点慢,不如手写的块。此外黄学长的std还有些问题:在更新的时候,std是将原来块内的部分删除掉,然后更新数据,再加入块内。这样就导致一个问题,如果原来块内有2个元素是相同的值,删除掉后就会认为块内没有这个值。所以正确的做法是,对暴力更新的部分,将set全部清空,更新完再全部加入。

在写程序的时候,还注意到两个问题:
1. 三步运算符比加法运算优先级要低,所以 num = n / block + (n%block)?1:0;的写法是不对的,如果非要这样写,要加括号。
2. 最后更新答案的时候,一定要考虑块的lazytag的值,否则结果自然不正确。

代码

方案一 块内sort

Accepted 100 4463 ms 2208 KiB

include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int nmax = 1e5 + 100;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int mm = sqrt(1e5 + 100) + 10;
int n;
ll data[nmax],tag[mm],temp[nmax];
int belong[nmax],L[mm],R[mm],block,num;
void init(){
    block = sqrt(n);
    num = n / block; if(n % block) num ++;
    for(int i = 1;i<=num;++i)
        L[i] = (i-1) * block + 1,
        R[i] = i * block;
    R[num] = n;
}
int main() {
    scanf("%d",&n);
    init();
    for(int i = 1;i<=n;++i){
        scanf("%lld",&data[i]);
        temp[i] = data[i];
        belong[i] = (i-1) / block + 1;
    }
    for(int i = 1;i<=num;++i) sort(temp + L[i],temp + R[i] + 1);
    int op,l,r; ll w;
    for(int i = 1;i<=n;++i){
        scanf("%d %d %d %lld",&op,&l,&r,&w);
        if(op == 0){
            if(belong[r] - belong[l] <= 1){
                for(int j = l;j<=r;++j) data[j] += w;
                for(int j = L[belong[l]]; j<=R[belong[r]];++j) temp[j] = data[j];
                sort(temp + L[belong[l]], temp + R[belong[l]] + 1);
                if(belong[r] != belong[l]) sort(temp + L[belong[r]], temp + R[belong[r]] + 1);
            }else{
                for(int j = l;j<=R[belong[l]];++j) data[j] += w;
                for(int j = L[belong[r]];j<=r;++j) data[j] += w;
                for(int j = belong[l] + 1;j<=belong[r]-1;++j) tag[j] += w;
                for(int j = L[belong[l]];j<=R[belong[l]];++j) temp[j] = data[j];
                for(int j = L[belong[r]];j<=R[belong[r]];++j) temp[j] = data[j];
                sort(temp + L[belong[l]], temp + R[belong[l]] + 1);
                sort(temp + L[belong[r]], temp + R[belong[r]] + 1);
            }
        }else{
            ll ans = -1; ll c = w;
            if(belong[r] - belong[l] <= 1){
                for(int j = l;j<=r;++j)
                    if(data[j] + tag[belong[j]] < c) ans = max(ans,data[j] + tag[belong[j]]);
            }else{
                for(int j = l;j<=R[belong[l]];++j)
                    if(data[j] + tag[belong[j]] < c) ans = max(ans,data[j] + tag[belong[j]]);
                for(int j = L[belong[r]];j<=r;++j)
                    if(data[j] + tag[belong[j]] < c) ans = max(ans,data[j] + tag[belong[j]]);
                for(int j = belong[l]+1;j<=belong[r]-1;++j){;
                    int pos = lower_bound(temp + L[j],temp + R[j] + 1, c - tag[j]) - (temp + L[j]);
                    if(pos == 0) continue;
                    else ans = max(ans,temp[L[j] + pos - 1] + tag[j]);
                }
            }
            printf("%lld\n",ans);
        }
    }
    return 0;
}

方案二 set维护有序

Accepted 100 9195 ms 4512 KiB



#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int nmax = 1e5 + 100;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int mm = sqrt(1e5 + 100) + 10;
int n,m;
set<ll> s[350];
ll data[nmax],tag[mm];
int L[mm],R[mm],belong[nmax],block,num;
void init(){
    block = sqrt(n);
    num = n / block; if(n%block) num ++;
    for(int i = 1;i<=num;++i)
        L[i] = (i-1) * block + 1,
        R[i] = i* block;
    R[num] = n;
}
int main() {
    scanf("%d",&n);
    init();
    for(int i = 1;i<=n;++i){
        scanf("%lld",&data[i]);
        belong[i] = (i-1) / block + 1;
        s[belong[i]].insert(data[i]);
    }
    int op,l,r; ll w;
    for(int i = 1 ;i<=n;++i){
        scanf("%d %d %d %lld",&op,&l,&r,&w);
        if(op == 0){
            if(belong[r] - belong[l] <=1){
                s[belong[l]].clear(); s[belong[r]].clear();
                for(int j = l;j<=r;++j) data[j] += w;
                for(int j = L[belong[l]];j<=R[belong[r]];++j) s[belong[j]].insert(data[j]);
            }else{
                s[belong[l]].clear();
                for(int j = l;j<=R[belong[l]];++j) data[j] += w;
                for(int j = L[belong[l]];j<=R[belong[l]];++j) s[belong[l]].insert(data[j]);
                s[belong[r]].clear();
                for(int j = L[belong[r]];j<=r;++j) data[j] += w;
                for(int j = L[belong[r]];j<=R[belong[r]];++j) s[belong[r]].insert(data[j]);
                for(int j = belong[l] + 1;j<=belong[r]-1;++j) tag[j] += w;
            }
        }else{
            ll ans = -INF;
            if(belong[r] - belong[l] <= 1){
                for(int j = l;j<=r;++j) if(data[j] + tag[belong[j]] < w) ans = max(ans,data[j] + tag[belong[j]]);
            }else{
                for(int j = l;j<=R[belong[l]];++j) if(data[j] + tag[belong[j]] < w) ans = max(ans, data[j] + tag[belong[j]]);
                for(int j = L[belong[r]];j<=r;++j) if(data[j] + tag[belong[j]] < w) ans = max(ans, data[j] + tag[belong[j]]);
                for(int j = belong[l] + 1; j<=belong[r]-1;++j){
                    set<ll> :: iterator it = s[j].lower_bound(w-tag[j]);
                    if(it == s[j].begin()) continue;
                    else {--it;ans = max(ans,*it + tag[j]);}
                }
            }
            if(ans == -INF) printf("-1\n");
            else printf("%lld\n",ans);
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/pengwill97/article/details/80918894
今日推荐