Description
sylvia 是一个热爱学习的女孩子,今天她想要学习数据结构技巧。 在看了一些博客学了一些姿势后,她想要找一些数据结构题来练练手。于是她的好朋友九条可怜酱给她出了一道题。 给出一个长度为 nn 的数列 AA,接下来有 mm 次操作,操作有三种:
对于所有的 i∈[l,r]i∈[l,r],将 Ai变成 Ai+x。
对于所有的 i∈[l,r]i∈[l,r],将 Ai变成 ⌊√Ai⌋。
对于所有的 i∈[l,r]i∈[l,r],询问 Ai的和。
作为一个不怎么熟练的初学者,sylvia 想了好久都没做出来。而可怜酱又外出旅游去了,一时间联系不上。于是她决定向你寻求帮助:你能帮她解决这个问题吗。
第一行两个数:n,m。 接下来一行 n个数 Ai。 接下来 m行中,第 i 行第一个数
ti
表示操作类型: 若
ti=1
,则接下来三个整数
li,ri,xi
,表示操作一。 若
ti=2
,则接下来三个整数
li,ri
,表示操作二。 若
ti=3
,则接下来三个整数
li,ri
,表示操作三。
Output
对于每个询问操作,输出一行表示答案。
5 5
1 2 3 4 5
1 3 5 2
2 1 4
3 2 4
2 3 5
3 1 5
Sample Output
5
6
Data
对于所有数据,保证有
1≤li≤ri≤n,1≤Ai,xi≤105
I think
我们来搞第二个操作。 单点修改变成 ⌊√Ai⌋是会TLE的。但是对于每一个数n,同样可以在近
log(n)
的时间里变为1,因此我们也可以用类似于【hdu5634】Rikka with Phi(线段树+欧拉函数) 的方法合并节点,不同的是本题有+x的操作。 我们维护区间最大最小值mx[i],mn[i],当一个区间满足
mx[i]==mn[i]
或
mx[i]−mn[i]==floor(sqrt(mx[i]))−floor(sqrt(mn[i]))
这个区间内的每个元素开根号之后的变化量相同,于是我们就可以很方便地更新了。
在传递添加值x时,尽管
x<=105
,但用x更新s[i]时需要
*1ll避免溢出。
Code
#include<cmath>
#include<cstdio>
using namespace std;
const int sm =
8e5+
50;
typedef long long LL;
int v,n,m;
LL s[sm],a[sm],mx[sm],mn[sm];
char ch;
template <
typename T> T Max(T x,T y) {
return x>y?x:y; }
template <
typename T> T Min(T x,T y) {
return x<y?x:y; }
template <
typename T>
void read(T &x) {
x=
0,ch=getchar();
while(ch>
'9'||ch<
'0') ch=getchar();
while(ch>=
'0'&&ch<=
'9') x=x*
10+ch-
'0',ch=getchar();
}
void update(
int i) {
s[i]=s[i<<
1]+s[i<<
1|
1];
mx[i]=Max(mx[i<<
1],mx[i<<
1|
1]);
mn[i]=Min(mn[i<<
1],mn[i<<
1|
1]);
}
void pd(
int i,
int l,
int r) {
int ls=i<<
1,rs=i<<
1|
1,m=(r+l)>>
1;
a[ls]+=a[i],a[rs]+=a[i];
s[ls]+=(m-l+
1)*a[i],s[rs]+=(r-m)*a[i];
mx[ls]+=a[i],mn[ls]+=a[i];
mx[rs]+=a[i],mn[rs]+=a[i];
a[i]=
0;
}
void build(
int i,
int l,
int r) {
if(l==r) {
read(v),s[i]=mx[i]=mn[i]=v;
return ;
}
int m=(l+r)>>
1;
build(i<<
1,l,m);
build(i<<
1|
1,m+
1,r);
update(i);
}
void add(
int i,
int l,
int r,
int ll,
int rr,
int val) {
if(ll<=l&&r<=rr) {
a[i]=
1ll*(a[i]+val),s[i]=s[i]+
1ll*(r-l+
1)*val;
mx[i]=
1ll*(mx[i]+val),mn[i]=
1ll*(mn[i]+val);
return ;
}
if(a[i])pd(i,l,r);
int m=(l+r)>>
1;
if(ll<=m) add(i<<
1,l,m,ll,rr,val);
if(rr> m) add(i<<
1|
1,m+
1,r,ll,rr,val);
update(i);
}
bool chk(
int i) {
return (mx[i]==mn[i])||(mx[i]-mn[i]==
floor(
sqrt(mx[i]))-
floor(
sqrt(mn[i])));
}
void modify(
int i,
int l,
int r,
int ll,
int rr) {
if(ll<=l&&r<=rr&&chk(i)) {
LL d=
floor(
sqrt(mx[i]))-mx[i];
mx[i]+=d,mn[i]+=d;
a[i]+=d,s[i]+=(r-l+
1)*d;
return;
}
if(a[i])pd(i,l,r);
int m=(l+r)>>
1;
if(ll<=m) modify(i<<
1,l,m,ll,rr);
if(rr> m) modify(i<<
1|
1,m+
1,r,ll,rr);
update(i);
}
LL query(
int i,
int l,
int r,
int ll,
int rr) {
if(ll<=l&&r<=rr)
return s[i];
if(a[i])pd(i,l,r);
int m=(l+r)>>
1;LL ans=
0;
if(ll<=m) ans+=query(i<<
1,l,m,ll,rr);
if(rr> m) ans+=query(i<<
1|
1,m+
1,r,ll,rr);
update(i);
return ans;
}
int main() {
read(n),read(m);
build(
1,
1,n);
int ind,l,r,x;
for(LL i=
1;i<=m;++i) {
read(ind),read(l),read(r);
if(ind==
1) read(x),add(
1,
1,n,l,r,x);
else if(ind==
2) modify(
1,
1,n,l,r);
else printf(
"%lld\n",query(
1,
1,n,l,r));
}
return 0;
}