题目描述
智乃酱最近在学习势能线段树
给你一个长度大小为N的正整数数组,进行M次操作,操作有下列两种。
- 给定区间[l,r]对区间中所有数字开根号向下取整,即ai=⌊ai⌋(l≤i≤r)。
- 给定区间[l,r],对区间中每个数字加上一个正整数x。
- 查询给定区间[l,r]的元素和,即求∑(i=l——r)ai。
链接:登录—专业IT笔试面试备考平台_牛客网
来源:牛客网
输入描述:
第一行输入两个正整数N,M(1≤N,M≤2×10^5)。
接下来一行输入N{N}N个正整数ai(1≤ai≤10^9)。
接下来M行,每行首先输入一个正整数op,(op∈{1,2})。
当op=1时,表示操作一,然后继续输入两个正整数l,r(1≤l≤r≤N)表示对[l,r]区间开根号向下取整。
当op=2时,表示操作二,然后继续输入三个正整数l,r,x(1≤l≤r≤N,1≤x≤10^4)表示给区间[l,r]{[l,r]}[l,r]加上一个正整数x。
当op=3时,表示操作二,然后继续输入两个正整数l,r(1≤l≤r≤N)l,表示求区间[l,r]的区间和。
输出描述:
对于每一个当op=3,输出区间和。
示例1
输入
10 3 10 10 10 10 10 10 10 10 10 10 3 1 10 1 1 5 3 1 10
输出
100 65
示例2
输入
10 3 10 10 10 10 10 10 10 10 10 10 1 1 5 2 1 10 5 3 1 10
输出
115
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+10;
ll a[N],n,m;
struct node
{
ll sum,mx,mn,lz;
} t[N*4];
ll ssqrt(int x)
{
return sqrt(x+0.5);
}
ll cal_dalta(int x)
{
return x-ssqrt(x);
}
void pushup(ll rt)
{
t[rt].sum=t[rt<<1].sum+t[rt<<1|1].sum;
t[rt].mx=max(t[rt<<1].mx,t[rt<<1|1].mx);
t[rt].mn=min(t[rt<<1].mn,t[rt<<1|1].mn);
}
void pushdown(ll rt,ll l,ll r)
{
if(t[rt].lz)
{
ll mid=(l+r)>>1;
t[rt<<1].sum+=t[rt].lz*(mid-l+1);
t[rt<<1|1].sum+=t[rt].lz*(r-mid);
t[rt<<1].mx+=t[rt].lz;
t[rt<<1].lz+=t[rt].lz;
t[rt<<1|1].mx+=t[rt].lz;
t[rt<<1].mn+=t[rt].lz;
t[rt<<1|1].mn+=t[rt].lz;
t[rt<<1|1].lz+=t[rt].lz;
t[rt].lz=0;
return;
}
return;
}
void build(ll rt,ll l,ll r)
{
t[rt].lz=0;
if(l==r)
{
t[rt].mn=t[rt].sum=t[rt].mx=a[l];
return;
}
ll mid=(l+r)>>1;
build(rt<<1,l,mid);
build(rt<<1|1,mid+1,r);
pushup(rt);
}
void update(ll rt,ll l,ll r,ll L,ll R,ll val)
{
if(L<=l&&r<=R)
{
t[rt].sum+=val*(r-l+1);
t[rt].mx+=val;
t[rt].mn+=val;
t[rt].lz+=val;
return ;
}
pushdown(rt,l,r);
ll mid=(l+r)>>1;
if(L<=mid) update(rt<<1,l,mid,L,R,val);
if(R>mid)update(rt<<1|1,mid+1,r,L,R,val);
pushup(rt);
}
void fuck(ll rt,ll l,ll r,ll L,ll R)
{
if(L<=l&&R>=r)
{
if(cal_dalta(t[rt].mx)==cal_dalta(t[rt].mn))
{
ll x=cal_dalta(t[rt].mx);
t[rt].sum-=x*(r-l+1);
t[rt].mx-=x;
t[rt].mn-=x;
t[rt].lz-=x;
return;
}
/* ll mid=(l+r)>>1;
fuck(rt<<1,l,mid,L,R);
fuck(rt<<1|1,mid+1,r,L,R);
pushup(rt);
return;*/
}
pushdown(rt,l,r);
ll mid=(l+r)>>1;
if(L<=mid) fuck(rt<<1,l,mid,L,R);
if(R>mid)fuck(rt<<1|1,mid+1,r,L,R);
pushup(rt);
}
ll query(ll rt,ll l,ll r,ll L,ll R)
{
if(L<=l&&R>=r)
{
return t[rt].sum;
}
pushdown(rt,l,r);
ll mid=(l+r)>>1;
ll ans=0;
if(mid >= R) ans=ans+query(rt<<1, l, mid, L, R);
else if(mid < L) ans=ans+query(rt<<1|1, mid + 1, r, L, R);
else
{
ans=ans+query(rt<<1, l, mid, L, mid)+query(rt<<1|1, mid + 1, r, mid + 1, R);
}
return ans;
}
signed main()
{
cin>>n>>m;
for(int i=1; i<=n; i++)
{
cin>>a[i];
}
build(1,1,n);
for(int i=1; i<=m; i++)
{
ll op,l,r;
cin>>op>>l>>r;
if(op==1)
{
fuck(1,1,n,l,r);
}
if(op==2)
{
cout<<query(1,1,n,l,r)<<"\n";
}
}
return 0;
}