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

题目链接

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

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

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

  2. Q l r,表示询问数列中第 \(l \sim r\) 个数的和。

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

输入格式

第一行两个整数 \(N,M\)

第二行 \(N\) 个整数 \(A[i]\)

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

输出格式

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

每个答案占一行。

数据范围

\(1 \le N,M \le 10^5\),
\(|d| \le 10000\),
\(|A[i]| \le 10^9\)

输入样例:

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线段树本质上是一个满二叉树,找叶子节点很方便,判断 \(l\)\(r\) 是否为兄弟节点也很方便:l^r=1

  • 时间复杂度:\(O(mlogn)\)

树状数组

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

\[\sum_{i=1}^{x} \sum_{j=1}^{i} b[j] \]

上式可以改写为:

\[\sum_{i=1}^{x} \sum_{j=1}^{i} b[j]=\sum_{i=1}^{x}(x-i+1) * b[i]=(x+1) \sum_{i=1}^{x} b[i]-\sum_{i=1}^{x} i * b[i] \]

维护两个树状数组即可

  • 时间复杂度:\(O(mlogn)\)

分块

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

  • 时间复杂度:\(O(m\sqrt{n})\)

代码

  • 线段树

    • 懒标记
// 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;
}
posted @ 2022-08-06 09:55  zyy2001  阅读(52)  评论(0编辑  收藏  举报