专栏文章

题解:P13977 数列分块入门 2

P13977题解参与者 1已保存评论 1

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
1 条
当前快照
1 份
快照标识符
@min00rjs
此快照首次捕获于
2025/12/01 18:20
3 个月前
此快照最后确认于
2025/12/01 18:20
3 个月前
查看原文

题解:P13977 数列分块入门 2

翻了一圈发现没有 Θ(nnlogn)\Theta(n\sqrt{n\log n}) 的做法,来发交一发题解。
首先,我们考虑分块,维护每个块的 tag 表示这个块每个数都要加上的数。
其次,每个块维护一个 vector 存下这个块内的数从小到大排序后的结果以方便查询。
发现修改散块暴力重构 Θ(BlogB)\Theta(B\log B) 的,整块是 Θ(nB)\Theta(\frac nB) 的。
查询散块枚举可以做到 Θ(B)\Theta(B),整块用 lower_bound 二分可以做到 Θ(nBlogB)\Theta(\frac nB\log B)
此时,取 B=nB=\sqrt n 可以做到 Θ(nnlogn)\Theta(n\sqrt n\log{\sqrt n})
但我们发现,其实修改散块时可以做到 Θ(B)\Theta(B)。具体的,修改一个散块时,把散块分为两部分,一部分为不修改的,一部分为修改的。发现这两部分提取出来后的相对顺序不会变,然后把这两部分归并即可。
于是可以做到 Θ(n(B+nBlogB))\Theta(n(B+\frac nB\log B)),取 B=nlognB=\sqrt{n\log n} 可以做到 Θ(nnlogn)\Theta(n\sqrt{n\log n})
代码:
CPP
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e5+5;
int n,m,a[N];
int b;
vector<pair<int,int>>r[N];
int g[N];
void re(int x,int ql,int qr){
	vector<pair<int,int>>o,d;
	for(int i=0,sz=r[x].size();i<sz;i++){
		int p=r[x][i].second;
		if(p>qr||p<ql)o.push_back({a[p],p});
		else d.push_back({a[p],p});
	}
	merge(o.begin(),o.end(),d.begin(),d.end(),r[x].begin());
}
void up(int ql,int qr,int v){
	if(ql/b==qr/b){
		for(int i=ql;i<=qr;i++)a[i]+=v;
		re(ql/b,ql,qr);
	}
	else{
		for(int i=ql;i<ql/b*b+b;i++)a[i]+=v;
		re(ql/b,ql,ql/b*b+b-1);
		for(int i=qr/b*b;i<=qr;i++)a[i]+=v;
		re(qr/b,qr/b*b,qr);
		for(int i=ql/b+1;i<qr/b;i++)g[i]+=v;
	}
}
int qy(int ql,int qr,int v){
	int ans=0;
	if(ql/b==qr/b){
		for(int i=ql;i<=qr;i++)ans+=(a[i]+g[ql/b]<v);
	}
	else{
		for(int i=ql;i<ql/b*b+b;i++)ans+=(a[i]+g[ql/b]<v);
		for(int i=qr/b*b;i<=qr;i++)ans+=(a[i]+g[qr/b]<v);
		for(int i=ql/b+1;i<qr/b;i++)ans+=lower_bound(r[i].begin(),r[i].end(),make_pair(v-g[i],-1))-r[i].begin();
	}
	return ans;
}
signed main(){
	ios::sync_with_stdio(0),cin.tie(0);
	cin>>n;b=sqrt(n*log(n));
	for(int i=0;i<n;i++)cin>>a[i],r[i/b].push_back({a[i],i});
	for(int i=0;i<=(n-1)/b;i++)sort(r[i].begin(),r[i].end());
	for(int i=1;i<=n;i++){
		int op,l,r,c;cin>>op>>l>>r>>c;
		--l,--r;
		if(op==0)up(l,r,c);
		else cout<<qy(l,r,c*c)<<'\n';
	}
	return 0;
}

评论

1 条评论,欢迎与作者交流。

正在加载评论...