线段树一命速通
2024-10-10 13:15:52
发布于:广东
83阅读
0回复
0点赞
这道题是一个典型的区间查询问题,具体代码如下(这是普通的写法,会TLE)
当然,这段代码运用了前缀和的思想,用空间换取了时间
#include <bits/stdc++.h>
#define ll long long
using namespace std;
constexpr ll MOD = 1e9 + 7;
int main() {
int n, _;
scanf("%d %d",&n,&_);
vector<ll> a(n),b(n+10);
for (auto &i:a)cin>>i;
b[0] = a[0];
for (int i = 1; i < n; i ++)
b[i] = a[i] - a[i - 1];
while (_ --) {
int x; scanf("%d",&x);
if (x == 1) {
int l, r, k;
scanf("%d %d %d",&l,&r,&k);
b[l - 1] += k;
b[r] -= k;
}
else {
int l, r; scanf("%d %d",&l,&r);
ll sum = 0;
a[0] = b[0];
for (int i = 1; i < n; i ++)
a[i] = a[i - 1] + b[i];
for (int i = l - 1; i < r; i ++) {
ll h = a[i];
h %= MOD;
h *= a[i];
h %= MOD;
h *= a[i];
h %= MOD;
sum = (sum + h + MOD) % MOD;
}
printf("%d\n",sum);
}
}
return 0;
}
所以我们需要用高级算法优化,这里要使用高级数据结构-线段树
具体代码如下
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAX=100005;
const ll MOD=1000000007;
ll sum1[4*MAX], sum2[4*MAX], sum3[4*MAX], lazyv[4*MAX];
ll A[MAX];
ll getMod(ll x){
ll res=x%MOD;
if(res<0) res+=MOD;
return res;
}
void build(int node, int l, int r){
if(l==r){
ll val = getMod(A[l]);
sum1[node]=val;
sum2[node]=(val*val)%MOD;
sum3[node]=(val*val%MOD*val)%MOD;
return;
}
int mid=(l+r)/2;
build(node*2,l,mid);
build(node*2+1,mid+1,r);
sum1[node]=(sum1[node*2]+sum1[node*2+1])%MOD;
sum2[node]=(sum2[node*2]+sum2[node*2+1])%MOD;
sum3[node]=(sum3[node*2]+sum3[node*2+1])%MOD;
}
void push_down(int node, int l, int r){
if(lazyv[node]==0) return;
ll K=lazyv[node];
int mid=(l+r)/2, left=node*2, right=node*2+1, cnt1=mid-l+1, cnt2=r-mid;
// Left child
ll s1=sum1[left], s2=sum2[left];
ll K2=(K*K)%MOD, K3=(K2*K)%MOD;
sum1[left]=(sum1[left]+K*cnt1)%MOD;
sum2[left]=(sum2[left]+(2*K*s1)%MOD + (K2*cnt1)%MOD)%MOD;
sum3[left]=(sum3[left]+(3*K*s2)%MOD + (3*K2*s1)%MOD + (K3*cnt1)%MOD)%MOD;
lazyv[left]=(lazyv[left]+K)%MOD;
// Right child
ll s1r=sum1[right], s2r=sum2[right];
sum1[right]=(sum1[right]+K*cnt2)%MOD;
sum2[right]=(sum2[right]+(2*K*s1r)%MOD + (K2*cnt2)%MOD)%MOD;
sum3[right]=(sum3[right]+(3*K*s2r)%MOD + (3*K2*s1r)%MOD + (K3*cnt2)%MOD)%MOD;
lazyv[right]=(lazyv[right]+K)%MOD;
lazyv[node]=0;
}
void update(int node, int l, int r, int L, int R, ll K){
if(R<l||r<L) return;
if(L<=l && r<=R){
ll cnt=r-l+1;
ll s1=sum1[node], s2=sum2[node];
ll K2=(K*K)%MOD, K3=(K2*K)%MOD;
sum1[node]=(sum1[node]+K*cnt)%MOD;
sum2[node]=(sum2[node]+(2*K*s1)%MOD + (K2*cnt)%MOD)%MOD;
sum3[node]=(sum3[node]+(3*K*s2)%MOD + (3*K2*s1)%MOD + (K3*cnt)%MOD)%MOD;
lazyv[node]=(lazyv[node]+K)%MOD;
return;
}
push_down(node,l,r);
int mid=(l+r)/2;
update(node*2,l,mid,L,R,K);
update(node*2+1,mid+1,r,L,R,K);
sum1[node]=(sum1[node*2]+sum1[node*2+1])%MOD;
sum2[node]=(sum2[node*2]+sum2[node*2+1])%MOD;
sum3[node]=(sum3[node*2]+sum3[node*2+1])%MOD;
}
ll query(int node, int l, int r, int L, int R){
if(R<l||r<L) return 0;
if(L<=l && r<=R) return sum3[node];
push_down(node,l,r);
int mid=(l+r)/2;
return (query(node*2,l,mid,L,R)+query(node*2+1,mid+1,r,L,R))%MOD;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
int N,M; cin>>N>>M;
for(int i=1;i<=N;i++) cin>>A[i];
build(1,1,N);
while(M--){
int type; cin>>type;
if(type==1){
int L,R; ll K; cin>>L>>R>>K;
K=getMod(K);
update(1,1,N,L,R,K);
}
else{
int L,R; cin>>L>>R;
ll ans=query(1,1,N,L,R);
ans=getMod(ans);
cout<<ans<<"\n";
}
}
return 0;
}
希望大家多多AC哦,希望这个题解能帮到你
觉得有用的可以点个赞
全部评论 4
前缀和时间好像也没换多少吧……
2024-11-07 来自 广东
0ding
2024-10-13 来自 广东
0顶
2024-10-09 来自 浙江
0顶!
2024-10-09 来自 广东
0
有帮助,赞一个