我与旧事归于尽,来年依旧迎花开|

dayz_break

园龄:7个月粉丝:5关注:6

[2023四校联考3]sakuya 题解(根号分治)

题目链接

题目分析

第一个操作类似哈希冲突那一道题,可以运用类似的思路开一个二维表,很容易想到两种做法:

  1. 开一个二维表,表上的第 i 行,第 j 列表示序列下标在模 i 意义下等于 j 的加法标记。对于修改操作,直接暴力修改对应的那一行的值即可,查询时用线段树查询那个区间的和,枚举每一行,用一个数据结构加上对应的加法标记即可。

  2. 线段树暴力修改区间。

设定一个数 w,当模数 w 时,进行第一种做法,否则进行第二种做法,当 w 约为 nlogn 时取到最优时间复杂度。

但是第一种操作的常数感觉要爆炸,将表上的第 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;
}

本文作者:dayz_break

本文链接:https://www.cnblogs.com/dayz-break/p/18440810

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   dayz_break  阅读(7)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起