数列分块<2>

本期是数列分块入门<2>。该系列的所有题目来自hzwer在LOJ上提供的数列分块入门系列。

Blog:http://hzwer.com/8053.html                       sto   hzwer   orz          %%%            [转载]

好像上面的链接↑打不开,放一个转载:https://www.cnblogs.com/ve-2021/articles/9135559.html

------------------------------------------------------------------------------------------------------------------------

LOJ-P6279:

接着第二题的解法,其实只要把块内查询的二分稍作修改即可。

不过这题其实想表达:可以在块内维护其它结构使其更具有拓展性,比如放一个set,这样如果还有插入、删除元素的操作,会更加的方便。

#include <bits/stdc++.h>
using namespace std;
const int maxn=10000S;
int a[maxn],idx[maxn],tag[maxn],tot=1000;
set<int> st[10S];
void change(int l,int r,int c){
    for(int i=l;i<=min(idx[l]*tot,r);i++){
        st[idx[l]].erase(a[i]);
        a[i]+=c;
        st[idx[l]].insert(a[i]);
    }
    if(idx[l]!=idx[r]){
        for(int i=(idx[r]-1)*tot+1;i<=r;i++){
            st[idx[r]].erase(a[i]);
            a[i]+=c;
            st[idx[r]].insert(a[i]);
        }
    }
    for(int i=idx[l]+1;i<=idx[r]-1;i++)
        tag[i]+=c;
}
int query(int l,int r,int c){
    int ans=-1;
    for(int i=l;i<=min(idx[l]*tot,r);i++){
        int val=a[i]+tag[idx[l]];
        if(val<c)
			ans=max(val,ans);
    }
    if(idx[l]!=idx[r]){     
        for(int i=(idx[r]-1)*tot+1;i<=r;i++){
            int val=a[i]+tag[idx[r]];
            if(val<c)
				ans=max(val,ans);
        }
    }
    for(int i=idx[l]+1;i<=idx[r]-1;i++){
        int x=c-tag[i];
        set<int>::iterator itr=st[i].lower_bound(x);
        if(itr==st[i].begin())
			continue;
        --itr;
        ans=max(ans,*itr+tag[i]);
    }
    return ans;
}
int main(){
	int n;
    cin>>n;
    for(int i=1;i<=n;i++)
    	cin>>a[i]; 
    for(int i=1;i<=n;i++){
        idx[i]=(i-1)/tot+1;
        st[idx[i]].insert(a[i]);
    }
    for(int i=1;i<=n;i++){
        int opt,l,r,c;
        cin>>opt>>l>>r>>c;
        if(opt==0)
			change(l,r,c);
        if(opt==1)
			cout<<query(l,r,c)<<endl;
    }
    return 0;
}

LOJ-P6280:

这题的询问变成了区间上的询问,不完整的块还是暴力;而要想快速统计完整块的答案,需要维护每个块的元素和,先要预处理一下。

考虑区间修改操作,不完整的块直接改,顺便更新块的元素和;完整的块类似之前标记的做法,直接根据块的元素和所加的值计算元素和的增量。

#include <bits/stdc++.h>
using namespace std;
int idx[50005],tot;
long long a[50005],tag[50005],sum[50005];
void change(int l,int r,int c){
    for(int i=l;i<=min(idx[l]*tot,r);i++){
        a[i]+=c;
		sum[idx[l]]+=c;
	}
    if(idx[l]!=idx[r]){
        for(int i=(idx[r]-1)*tot+1;i<=r;i++){
            a[i]+=c;
			sum[idx[r]]+=c;
		}
    }
    for(int i=idx[l]+1;i<=idx[r]-1;i++)
        tag[i]+=c;
}
long long query(int l,int r){
    long long ans=0;
    for(int i=l;i<=min(idx[l]*tot,r);i++)
        ans+=a[i]+tag[idx[l]];
    if(idx[l]!=idx[r]){
        for(int i=(idx[r]-1)*tot+1;i<=r;i++)
            ans+=a[i]+tag[idx[r]];
    }
    for(int i=idx[l]+1;i<=idx[r]-1;i++)
        ans+=sum[i]+tot*tag[i];
    return ans;
}
int main(){
	int n;
    cin>>n;
	tot=sqrt(n);
    for(int i=1;i<=n;i++)
		cin>>a[i];
    for(int i=1;i<=n;i++){
        idx[i]=(i-1)/tot+1;
        sum[idx[i]]+=a[i];
    }
    for(int i=1;i<=n;i++){
        int opt,l,r,c;
        cin>>opt>>l>>r>>c; 
        if(opt==O)
			change(l,r,c);
        if(opt==1)
            cout<<query(l,r)%(c+1)<<endl;
    }
    return 0;
}

LOJ-P6281:

稍作思考可以发现,开方操作比较棘手,主要是对于整块开方时,必须要知道每一个元素,才能知道他们开方后的和,也就是说,难以快速对一个块信息进行更新。

看来我们要另辟蹊径。不难发现,这题的修改就只有下取整开方,而一个数经过几次开方之后,它的值就会变成0或者1

如果每次区间开方只不涉及完整的块,意味着不超过2\sqrt{n}个元素,直接暴力即可。

如果涉及了一些完整的块,这些块经过几次操作以后就会都变成01,于是我们采取一种分块优化的暴力做法,只要每个整块暴力开方后,记录一下元素是否都变成了01,区间修改时跳过那些全为01的块即可。

这样每个元素至多被开方不超过4次,显然复杂度没有问题。

#include <bits/stdc++.h> 
using namespace std;
int a[50005],sum[50005],idx[50005],tot;
bool flag[50005];
void solve(int x){
    if(flag[x])
		return;
    flag[x]=1;
    sum[x]=0;
    for(int i=(x-1)*tot+1;i<=x*tot;i++){
        a[i]=sqrt(a[i]);
		sum[x]+=a[i];
        if(a[i]>1)
			flag[x]=0;
    }
}
void change(int l,int r,int c){
    for(int i=l;i<=min(idx[l]*tot,r);i++){
        sum[idx[l]]-=a[i];
        a[i]=sqrt(a[i]);
        sum[idx[l]]+=a[i];
    }
    if(idx[l]!=idx[r]){
        for(int i=(idx[r]-1)*tot+1;i<=r;i++){
            sum[idx[r]]-=a[i];
            a[i]=sqrt(a[i]);
            sum[idx[r]]+=a[i];
        }
    }
    for(int i=idx[l]+1;i<=idx[r]-1;i++)
        solve(i);
}
int query(int l,int r){
    int ans=0;
    for(int i=l;i<=min(idx[l]*tot,r);i++)
        ans+=a[i];
    if(idx[l]!=idx[r]){
        for(int i=(idx[r]-1)*tot+1;i<=r;i++)
            ans+=a[i];
    }
    for(int i=idx[l]+1;i<=idx[r]-1;i++)
        ans+=sum[i];
    return ans;
}
int main(){
	int n;
    cin>>n;
	tot=sqrt(n);
    for(int i=1;i<=n;i++)
		cin>>a[i];
    for(int i=1;i<=n;i++){
        idx[i]=(i-1)/tot+1;
        sum[idx[i]]+=a[i];
    }
    for(int i=1;i<=n;i++){
        int opt,l,r,c;
        cin>>opt>>l>>r>>c;
        if(opt==0)
			change(l,r,c);
        if(opt==l)
            cout<<query(l,r)<<endl;
    }
    return 0;
}

友情提醒:不要Ctrl C+Ctrl V

相关推荐

  1. 数据分析---SQL(2)

    2024-07-12 00:34:05       57 阅读
  2. 数据分析-pandas2

    2024-07-12 00:34:05       23 阅读
  3. 数据分析---SQL实战(2

    2024-07-12 00:34:05       46 阅读
  4. 智能数据分析2)Lecture 9-11

    2024-07-12 00:34:05       27 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-12 00:34:05       66 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-12 00:34:05       70 阅读
  3. 在Django里面运行非项目文件

    2024-07-12 00:34:05       57 阅读
  4. Python语言-面向对象

    2024-07-12 00:34:05       68 阅读

热门阅读

  1. mvvm模式

    2024-07-12 00:34:05       26 阅读
  2. Mybatis-Plus最优化持久层开发

    2024-07-12 00:34:05       21 阅读
  3. C++ 定时器触发

    2024-07-12 00:34:05       24 阅读
  4. SqlSugar分表笔记

    2024-07-12 00:34:05       25 阅读
  5. 模板语法指令语法——02

    2024-07-12 00:34:05       21 阅读
  6. LeetCode 算法:实现 Trie (前缀树) c++

    2024-07-12 00:34:05       21 阅读