243. 一个简单的整数问题2

题目链接

243. 一个简单的整数问题2

给定一个长度为 N 的数列 A,以及 M 条指令,每条指令可能是以下两种之一:

  1. C l r d,表示把 A[l],A[l+1],,A[r] 都加上 d

  2. Q l r,表示询问数列中第 lr 个数的和。

对于每个询问,输出一个整数表示答案。

输入格式

第一行两个整数 N,M

第二行 N 个整数 A[i]

接下来 M 行表示 M 条指令,每条指令的格式如题目描述所示。

输出格式

对于每个询问,输出一个整数表示答案。

每个答案占一行。

数据范围

1N,M105,
|d|10000,
|A[i]|109

输入样例:

10 5 1 2 3 4 5 6 7 8 9 10 Q 4 4 Q 1 10 Q 2 4 C 3 6 3 Q 2 4

输出样例:

4 55 9 15

解题思路

线段树

线段树模板题,有打懒标记和标记永久化两种做法

  • 懒标记:即每次操作需要将标记下传,即动态修改信息

  • 标记永久化:有局限性,不能处理相互的影响的多个标记,维护整个区间,标记打到表示整个区间的节点上时就不再往下传,而是在查询记录结果时加上往下传的标记带来的贡献

  • 时间复杂度:O(mlogn)

zkw线段树

相对于普通线段树而言,码量更小,常数更小,大多数情况下能够取代普通线段树,但是不能处理维护优先级的信息(如区间加和乘的混合运算),一般自底向上维护信息,原因在于zkw线段树本质上是一个满二叉树,找叶子节点很方便,判断 lr 是否为兄弟节点也很方便:l^r=1

  • 时间复杂度:O(mlogn)

树状数组

维护一个差分数组 b[i]i=1xb[i] 即为 a[x] 变化的值,同理可得序列 a 的前缀和 a[1x]. 整体增加的值就是:

i=1xj=1ib[j]

上式可以改写为:

i=1xj=1ib[j]=i=1x(xi+1)b[i]=(x+1)i=1xb[i]i=1xib[i]

维护两个树状数组即可

  • 时间复杂度:O(mlogn)

分块

1n 的整个区间分为 n 个小区间,每次修改或询问采用全局标记,局部朴素的思想,即将所有完全包含 n 个数的区间标记,其他暴力求解,两部分的复杂度都为 O(n),这样每次修改或询问都为 O(n)

  • 时间复杂度:O(mn)

代码

  • 线段树

    • 懒标记
// Problem: 一个简单的整数问题2 // Contest: AcWing // URL: https://www.acwing.com/problem/content/description/244/ // Memory Limit: 64 MB // Time Limit: 1000 ms // // Powered by CP Editor (https://cpeditor.org) // %%%Skyqwq #include <bits/stdc++.h> //#define int long long #define help {cin.tie(NULL); cout.tie(NULL);} #define pb push_back #define fi first #define se second #define mkp make_pair using namespace std; typedef long long LL; typedef pair<int, int> PII; typedef pair<LL, LL> PLL; template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; } template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; } template <typename T> void inline read(T &x) { int f = 1; x = 0; char s = getchar(); while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); } while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar(); x *= f; } const int N=100005; int n,m,a[N]; struct Tr { int l,r; LL sum,add; }tr[N<<2]; void pushup(int u) { tr[u].sum=tr[u<<1].sum+tr[u<<1|1].sum; } void pushdown(int u) { if(tr[u].add) { tr[u<<1].sum+=tr[u].add*(tr[u<<1].r-tr[u<<1].l+1); tr[u<<1|1].sum+=tr[u].add*(tr[u<<1|1].r-tr[u<<1|1].l+1); tr[u<<1].add+=tr[u].add,tr[u<<1|1].add+=tr[u].add; tr[u].add=0; } } void build(int u,int l,int r) { tr[u]={l,r,0,0}; if(l==r) { tr[u].sum=a[l]; return ; } int mid=l+r>>1; build(u<<1,l,mid),build(u<<1|1,mid+1,r); pushup(u); } void change(int u,int l,int r,int d) { if(l<=tr[u].l&&tr[u].r<=r) { tr[u].sum+=d*(tr[u].r-tr[u].l+1); tr[u].add+=d; return ; } pushdown(u); int mid=tr[u].l+tr[u].r>>1; if(l<=mid)change(u<<1,l,r,d); if(r>mid)change(u<<1|1,l,r,d); pushup(u); } LL ask(int u,int l,int r) { if(l<=tr[u].l&&tr[u].r<=r)return tr[u].sum; int mid=tr[u].l+tr[u].r>>1; pushdown(u); LL res=0; if(l<=mid)res+=ask(u<<1,l,r); if(r>mid)res+=ask(u<<1|1,l,r); return res; } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++)scanf("%d",&a[i]); build(1,1,n); while(m--) { char op[2]; int l,r,d; scanf("%s%d%d",op,&l,&r); if(*op=='Q')printf("%lld\n",ask(1,l,r)); else { scanf("%d",&d); change(1,l,r,d); } } return 0; }
    • 标记永久化
// Problem: 一个简单的整数问题2 // Contest: AcWing // URL: https://www.acwing.com/problem/content/244/ // Memory Limit: 64 MB // Time Limit: 1000 ms // // Powered by CP Editor (https://cpeditor.org) // %%%Skyqwq #include <bits/stdc++.h> // #define int long long #define help {cin.tie(NULL); cout.tie(NULL);} #define pb push_back #define fi first #define se second #define mkp make_pair using namespace std; typedef long long LL; typedef pair<int, int> PII; typedef pair<LL, LL> PLL; template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; } template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; } template <typename T> void inline read(T &x) { int f = 1; x = 0; char s = getchar(); while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); } while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar(); x *= f; } const int N=1e5+5; int n,m; struct Tr { int l,r; LL add,sum; }tr[N<<2]; void build(int u,int l,int r) { tr[u].l=l,tr[u].r=r; if(l==r) { scanf("%lld",&tr[u].sum); return ; } int mid=l+r>>1; build(u<<1,l,mid),build(u<<1|1,mid+1,r); tr[u].sum=tr[u<<1].sum+tr[u<<1|1].sum; } void change(int u,int l,int r,int d) { if(l<=tr[u].l&&tr[u].r<=r) { tr[u].sum+=(tr[u].r-tr[u].l+1)*d; tr[u].add+=d; return ; } int mid=tr[u].l+tr[u].r>>1; if(l<=mid)change(u<<1,l,r,d); if(r>mid)change(u<<1|1,l,r,d); tr[u].sum=tr[u<<1].sum+tr[u<<1|1].sum+(tr[u].r-tr[u].l+1)*tr[u].add; } LL ask(int u,int l,int r) { if(l<=tr[u].l&&tr[u].r<=r)return tr[u].sum; LL res=tr[u].add*(min(tr[u].r,r)-max(tr[u].l,l)+1); int mid=tr[u].l+tr[u].r>>1; if(l<=mid)res+=ask(u<<1,l,r); if(r>mid)res+=ask(u<<1|1,l,r); return res; } int main() { scanf("%d%d",&n,&m); build(1,1,n); while(m--) { char op[2]; int l,r,d; scanf("%s%d%d",op,&l,&r); if(*op=='Q')printf("%lld\n",ask(1,l,r)); else { scanf("%d",&d); change(1,l,r,d); } } return 0; }
  • zkw线段树
// Problem: 一个简单的整数问题2 // Contest: AcWing // URL: https://www.acwing.com/problem/content/244/ // Memory Limit: 64 MB // Time Limit: 1000 ms // // Powered by CP Editor (https://cpeditor.org) // %%%Skyqwq #include <bits/stdc++.h> //#define int long long #define help {cin.tie(NULL); cout.tie(NULL);} #define pb push_back #define fi first #define se second #define mkp make_pair using namespace std; typedef long long LL; typedef pair<int, int> PII; typedef pair<LL, LL> PLL; template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; } template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; } template <typename T> void inline read(T &x) { int f = 1; x = 0; char s = getchar(); while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); } while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar(); x *= f; } const int N=1e5+5; int n,m,l,r,d; char op[2]; int cnt=1; LL sum[N<<2],add[N<<2]; void build() { for(;cnt<=n+1;cnt<<=1); for(int i=cnt+1;i<=cnt+n;i++)scanf("%lld",&sum[i]); for(int i=cnt-1;i;i--)sum[i]=sum[i<<1]+sum[i<<1|1]; } void change(int l,int r,int d) { int lnum=0,rnum=0,nnum=1; for(l=l+cnt-1,r=r+cnt+1;l^r^1;l>>=1,r>>=1,nnum<<=1) { sum[l]+=d*lnum,sum[r]+=d*rnum; if(~l&1)add[l^1]+=d,sum[l^1]+=(LL)d*nnum,lnum+=nnum; if(r&1)add[r^1]+=d,sum[r^1]+=(LL)d*nnum,rnum+=nnum; } for(;l;l>>=1,r>>=1)sum[l]+=(LL)d*lnum,sum[r]+=(LL)d*rnum; } LL ask(int l,int r) { LL res=0; int lnum=0,rnum=0,nnum=1; for(l=l+cnt-1,r=r+cnt+1;l^r^1;l>>=1,r>>=1,nnum<<=1) { if(add[l])res+=(LL)add[l]*lnum; if(add[r])res+=(LL)add[r]*rnum; if(~l&1)res+=sum[l^1],lnum+=nnum; if(r&1)res+=sum[r^1],rnum+=nnum; } for(;l;l>>=1,r>>=1)res+=(LL)add[l]*lnum+(LL)add[r]*rnum; return res; } int main() { scanf("%d%d",&n,&m); build(); while(m--) { scanf("%s%d%d",op,&l,&r); if(*op=='C') { scanf("%d",&d); change(l,r,d); } else printf("%lld\n",ask(l,r)); } return 0; }
  • 树状数组
// Problem: 一个简单的整数问题2 // Contest: AcWing // URL: https://www.acwing.com/problem/content/description/244/ // Memory Limit: 64 MB // Time Limit: 1000 ms // // Powered by CP Editor (https://cpeditor.org) // %%%Skyqwq #include <bits/stdc++.h> // #define int long long #define help {cin.tie(NULL); cout.tie(NULL);} #define pb push_back #define fi first #define se second #define mkp make_pair using namespace std; typedef long long LL; typedef pair<int, int> PII; typedef pair<LL, LL> PLL; template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; } template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; } template <typename T> void inline read(T &x) { int f = 1; x = 0; char s = getchar(); while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); } while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar(); x *= f; } const int N=1e5+5; int n,m; LL s[N],tr[2][N]; void add(int ty,int x,int y) { for(;x<N;x+=x&-x)tr[ty][x]+=y; } LL ask(int ty,int x) { LL res=0; for(;x;x-=x&-x)res+=tr[ty][x]; return res; } int main() { scanf("%lld%lld",&n,&m); for(int i=1;i<=n;i++)scanf("%lld",&s[i]),s[i]+=s[i-1]; while(m--) { char op[2]; int l,r,d; scanf("%s%d%d",op,&l,&r); if(*op=='Q')printf("%lld\n",s[r]-s[l-1]+(r+1)*ask(0,r)-ask(1,r)-((l-1+1)*ask(0,l-1)-ask(1,l-1))); else { scanf("%d",&d); add(0,l,d),add(1,l,l*d); add(0,r+1,-d),add(1,r+1,(r+1)*-d); } } return 0; }
  • 分块
// Problem: 一个简单的整数问题2 // Contest: AcWing // URL: https://www.acwing.com/problem/content/description/244/ // Memory Limit: 64 MB // Time Limit: 1000 ms // // Powered by CP Editor (https://cpeditor.org) // %%%Skyqwq #include <bits/stdc++.h> //#define int long long #define help {cin.tie(NULL); cout.tie(NULL);} #define pb push_back #define fi first #define se second #define mkp make_pair using namespace std; typedef long long LL; typedef pair<int, int> PII; typedef pair<LL, LL> PLL; template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; } template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; } template <typename T> void inline read(T &x) { int f = 1; x = 0; char s = getchar(); while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); } while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar(); x *= f; } const int N=350,M=1e5+5; int n,m,a[M],len; LL add[N],sum[N]; int get(int x) { return x/len; } void change(int l,int r,int d) { if(get(l)==get(r))for(int i=l;i<=r;i++)a[i]+=d,sum[get(i)]+=d; else { int i=l,j=r; while(get(i)==get(l))a[i]+=d,sum[get(i)]+=d,i++; while(get(j)==get(r))a[j]+=d,sum[get(j)]+=d,j--; for(int k=get(i);k<=get(j);k++)sum[k]+=len*d,add[k]+=d; } } LL ask(int l,int r) { LL res=0; if(get(l)==get(r))for(int i=l;i<=r;i++)res+=a[i]+add[get(i)]; else { int i=l,j=r; while(get(i)==get(l))res+=a[i]+add[get(i)],i++; while(get(j)==get(r))res+=a[j]+add[get(j)],j--; for(int k=get(i);k<=get(j);k++)res+=sum[k]; } return res; } int main() { scanf("%d%d",&n,&m); len=sqrt(n); for(int i=1;i<=n;i++)scanf("%d",&a[i]),sum[get(i)]+=a[i]; while(m--) { char op[2]; int l,r,d; scanf("%s%d%d",op,&l,&r); if(*op=='Q')printf("%lld\n",ask(l,r)); else { scanf("%d",&d); change(l,r,d); } } return 0; }

__EOF__

本文作者acwing_zyy
本文链接https://www.cnblogs.com/zyyun/p/16556517.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   zyy2001  阅读(55)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示