[2023四校联考3]sakuya 题解(根号分治)
题目链接。
题目分析
第一个操作类似哈希冲突那一道题,可以运用类似的思路开一个二维表,很容易想到两种做法:
- 
开一个二维表,表上的第 \(i\) 行,第 \(j\) 列表示序列下标在模 \(i\) 意义下等于 \(j\) 的加法标记。对于修改操作,直接暴力修改对应的那一行的值即可,查询时用线段树查询那个区间的和,枚举每一行,用一个数据结构加上对应的加法标记即可。
 - 
线段树暴力修改区间。
 
设定一个数 \(w\),当模数 \(\le w\) 时,进行第一种做法,否则进行第二种做法,当 \(w\) 约为 \(\sqrt{n\log n}\) 时取到最优时间复杂度。
但是第一种操作的常数感觉要爆炸,将表上的第 \(i\) 行,第 \(j\) 列的含义转变为那一行加法标记的前缀和,于是便可以做到每行 \(O(1)\) 计算贡献,注意细节即可。
#include<bits/stdc++.h>
using namespace std;
inline long long read(){
	long long 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<<1)+(x<<3)+(ch^48),ch=getchar();
	return x*f;
}
const int maxn=2e5+20;
long long n,m,a[maxn],len;
struct node{
	long long tag,sum;
}tree[maxn<<2];
struct segment_tree{
	inline long long ls(int x){
		return x<<1;
	}
	inline long long rs(int x){
		return x<<1|1;
	}
	inline void push_up(int p){
		tree[p].sum=tree[ls(p)].sum+tree[rs(p)].sum;
	}
	void build(int p,int l,int r){
		if(l==r){
			tree[p].sum=a[l];
			return;
		}
		int mid=l+r>>1;
		build(ls(p),l,mid);
		build(rs(p),mid+1,r);
		push_up(p);
	}
	inline void push_down(int p,int l,int r){
		int mid=l+r>>1;
		tree[ls(p)].sum+=tree[p].tag*(mid-l+1),tree[rs(p)].sum+=tree[p].tag*(r-mid);
		tree[ls(p)].tag+=tree[p].tag,tree[rs(p)].tag+=tree[p].tag;
		tree[p].tag=0;
	}
	void update(int p,int l,int r,int x,int y,long long k){
		if(x<=l&&r<=y){
			tree[p].tag+=k,tree[p].sum+=k*(r-l+1);
			return;
		}
		push_down(p,l,r);
		int mid=l+r>>1;
		if(x<=mid) update(ls(p),l,mid,x,y,k);
		if(y>mid) update(rs(p),mid+1,r,x,y,k);
		push_up(p);
	}
	long long query(int p,int l,int r,int x,int y){
		if(x<=l&&r<=y) return tree[p].sum;
		push_down(p,l,r);
		int mid=l+r>>1;
		if(y<=mid) return query(ls(p),l,mid,x,y);
		if(x>mid) return query(rs(p),mid+1,r,x,y);
		return query(ls(p),l,mid,x,y)+query(rs(p),mid+1,r,x,y);
	}
}S;
long long f[1000][1000];
inline void solve2(long long x,long long y,long long k){
	if(x-1<=y) S.update(1,1,n,1,n,k);
	else for(int i=0;i<n;i+=x) S.update(1,1,n,i+1,min({n,i+y+1,i+x}),k);
}
inline void solve1(long long x,long long y,long long k){
	for(int i=0;i<=min(y,x-1);i++) f[x][i]+=(i+1)*k;
	for(int i=y+1;i<x;i++) f[x][i]+=(min(y,x-1)+1)*k;
}
inline void solve3(long long x,long long y){
	long long res=S.query(1,1,n,x,y);
	--x,--y;
	long long l,r;
	for(int i=1;i<=len;i++){
		l=(long long)ceil(1.0*x/i)*i-x,r=y-(long long)floor(1.0*y/i)*i;
		res+=f[i][i-1]-f[i][i-l-1],res+=f[i][r];
		res+=f[i][i-1]*((y/i)-(long long)ceil(1.0*x/i));
	}
	
	printf("%lld\n",res);
}
int main(){
	n=read(),m=read();
	len=990;
	for(int i=1;i<=n;i++) a[i]=read();
	S.build(1,1,n);
	long long op,x,y,k;
	for(int j=1;j<=m;j++){
		op=read(),x=read(),y=read();
		if(op==1) k=read();
		if(op==1&&x<=len) solve1(x,y,k);
		else if(op==1&&x>len) solve2(x,y,k);
		else if(op==2) solve3(x,y);
	}
	return 0;
}

                
            
        
浙公网安备 33010602011771号