LOJ #6278 数列分块2题解 && 2024年第一篇题解

Part #0 . 前言 \text{Part \#0 . 前言} Part #0 . 前言

数列分块1

分块是一种优雅的暴力。


Part #1 . 数列分块入门2 \text{Part \#1 . 数列分块入门2} Part #1 . 数列分块入门2

传送门

观察题目,我们可以发现题目是一个区间查询,区间修改。
首先,题目要求查询的是小于 c 2 c^2 c2 的数的 个数 。 所以可以通过排序之后用 lower_bound 减初始坐标即可。

但是由于是区间修改,所以每一次在修改之后都要对当前所在的块进行一个更新。

代码如下:

inline void update(int x)
{
	v[x].clear();
	forz(i,st[x],ed[x]) v[x].push_back(a[i]);
	sort(v[x].begin(),v[x].end());
}
if(block[l]==block[r])
{
	forz(i,l,r) a[i]+=c;
	update(block[l]);
}
else
{
	forz(i,l,ed[block[l]]) a[i]+=c;
	update(block[l]);
	forz(i,block[l]+1,block[r]-1) fk[i]+=c;
	forz(i,st[block[r]],r) a[i]+=c;
	update(block[r]);
}

接着来讨论一下区间查询,还是先分两种情况:是否在同一个块内。

  • 如果在同一个块内,可以直接暴力求得答案,复杂度 O ( n ) O(\sqrt{n}) O(n )
  • 如果不在同一个块内,两边非整块的部分暴力,中间用 lower_bound 来求,总复杂度 O ( n + log ⁡ n ) O(\sqrt{n}+\log{n}) O(n +logn)

整一个程序如下,时间复杂度 O ( n n + n log ⁡ n ) O(n\sqrt{n}+n \log n) O(nn +nlogn)

/*
1. sqrt(m*2/3)
*/
#include 

using namespace std;

#define int long long
#define fi first
#define se second
#define rg register
#define il inline
#define forz(i,a,b) for(register int i((a));i<=(b);++i)
#define forn(i,a,b) for(register int i((a));i>=(b);--i)
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)

inline int read()
{
	int x=0,f=1;
	char ch=getchar();
	while (ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}
	while (ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
	return x*f;
}

inline void write(int x)
{
    if(x<0){putchar('-');x=-x;}
    if(x>9) write(x/10);
    putchar(x%10+'0');
}

const int maxn=5e4+100;
const int mod=993244853;
const int inf=9e18;

int a[maxn];
int fk[maxn];
int st[maxn],ed[maxn],lenn[maxn];
int block[maxn];
int num,len;
vector<int> v[maxn];

inline void init(int n)
{
	len=sqrt(n);
	num=n%len?n/len+1:n/len;
	forz(i,1,num)
	{
		st[i]=(i-1)*len+1;
		ed[i]=min(n,i*len);
		lenn[i]=ed[i]-st[i]+1;
	}
	forz(i,1,num) forz(j,st[i],ed[i]) block[j]=i;
}

inline void update(int x)
{
	v[x].clear();
	forz(i,st[x],ed[x]) v[x].push_back(a[i]);
	sort(v[x].begin(),v[x].end());
}

inline void solve()
{
	int n=read();init(n);
	forz(i,1,n)
	{
		a[i]=read();
		v[block[i]].push_back(a[i]);
	}
	forz(i,1,num) sort(v[i].begin(),v[i].end());
	while (n--)
	{
		int op=read(),l=read(),r=read(),c=read();
		if(!op)
		{
			if(block[l]==block[r])
			{
				forz(i,l,r) a[i]+=c;
				update(block[l]);
			}
			else
			{
				forz(i,l,ed[block[l]]) a[i]+=c;
				update(block[l]);
				forz(i,block[l]+1,block[r]-1) fk[i]+=c;
				forz(i,st[block[r]],r) a[i]+=c;
				update(block[r]);
			}
		}
		else
		{
			int cnt=0;
			if(block[l]==block[r])
			{
				forz(i,l,r) if(a[i]+fk[block[i]]<c*c) cnt++;
			}
			else
			{
				forz(i,l,ed[block[l]]) if(a[i]+fk[block[i]]<c*c) cnt++;
				forz(i,block[l]+1,block[r]-1)
				{
					int ans=c*c-fk[i];                     
					cnt+=lower_bound(v[i].begin(),v[i].end(),ans)-v[i].begin();
				}
				forz(i,st[block[r]],r) if(a[i]+fk[block[i]]<c*c) cnt++;
			}
			write(cnt);
			putchar('\n');
		}
	}            
	putchar('\n'); 
}

signed main()
{
//    IOS;
	int _=1;
	while (_--) solve();
	return 0;
}

已经2024年了,祝大家在2024年一帆风顺,前途似锦,期末取得佳绩。

你可能感兴趣的:(code,洛谷题解,CSP冲刺,c++,算法,笔记)