欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

CodeVs 1082

程序员文章站 2022-03-09 19:36:02
...

传送门 :线段树练习

线段树 区间修改 + 区间查询


题目描述 Description

给你N个数,有两种操作:


1:给区间[a,b]的所有数增加X


2:询问区间[a,b]的数的和。

输入描述 Input Description

第一行一个正整数n,接下来n行n个整数,

 

再接下来一个正整数Q,每行表示操作的个数,

 

如果第一个数是1,后接3个正整数,

 

表示在区间[a,b]内每个数增加X,如果是2,

 

表示操作2询问区间[a,b]的和是多少。


pascal选手请不要使用readln读入

输出描述 Output Description

对于每个询问输出一行一个答案

样例输入 Sample Input

3

1

2

3

2

1 2 3 2

2 2 3

样例输出 Sample Output

9

数据范围及提示 Data Size & Hint

数据范围

1<=n<=200000

1<=q<=200000


线段树区间修改+ 区间查询

#include<iostream>
#include<cstdio>
using namespace std;
int n,m,op,x,y,val;
long long ans;
struct Tree{
	int l;
	int r;
	long long w;
	int f;
}tree[200000*5+100];
void build(int k,int l,int r)
{
	tree[k].l = l;
	tree[k].r = r;
	if(l == r)
	{
		scanf("%d",&tree[k].w);
		return ;
	}
	int m = (tree[k].l + tree[k].r )>>1;
	build(k<<1,l,m);
	build(k<<1|1,m+1,r);
	tree[k].w = tree[k<<1].w + tree[k<<1|1].w;
}
void down(int k)
{
	tree[k<<1].f +=tree[k].f;
	tree[k<<1|1].f+= tree[k].f;
	tree[k<<1].w += (tree[k<<1].r - tree[k<<1].l +1)*tree[k].f;
	tree[k<<1|1].w += (tree[k<<1|1].r - tree[k<<1|1].l+1)*tree[k].f;
	tree[k].f = 0;
}
void add(int k)
{
	if(tree[k].l >=x&&tree[k].r<=y)
	{
		tree[k].w += (tree[k].r - tree[k].l + 1) * val;
		tree[k].f += val;
		return ; 
	}
	if(tree[k].f ) down(k);
	int m = (tree[k].l + tree[k].r)>>1;
	if(x<=m) add(k<<1);
	if(y>m) add(k<<1|1);
	tree[k].w = tree[k<<1].w + tree[k<<1|1].w; 
}
void ask(int k)
{
	if(tree[k].l>=x&&tree[k].r<=y)
	{
		ans += tree[k].w;
		return ;
	}
	if(tree[k].f) down(k);
	int m = (tree[k].l + tree[k].r) >>1;
	if(x<=m) ask(k<<1);
	if(y>m) ask(k<<1|1);
}
int main()
{
	scanf("%d",&n);
	build(1,1,n);
	scanf("%d",&m);
	while(m--)
	{
		
		scanf("%d%d%d",&op,&x,&y);
		if(op == 1)
		{
			scanf("%d",&val);
			add(1);
		}
		else {
			ans = 0;
			ask(1);
			printf("%d\n",ans);
		}
	}
	return 0;
}


ZKW 线段树

#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int maxn = 200000 + 5;
int n, M;
LL sum[maxn << 2], add[maxn << 2];

void build() {
    M = 1; 
    while(M < (n + 2)) M <<= 1;
    for (int i = 1; i <= n; i++) {
        int x = M + i;
        scanf("%lld", sum + x);
        while(x >>= 1) sum[x] = sum[x << 1] + sum[x << 1 | 1];
    }
}

void update(int l, int r, LL x) {
    l += M - 1, r += M + 1;
    int L = 0, R = 0;
    for (int i = 1; l ^ r ^ 1; i <<= 1, l >>= 1, r >>= 1) {
        sum[l] += L * x, sum[r] += R * x;
        if(~l & 1) add[l ^ 1] += x, sum[l ^ 1] += i * x, L += i;
        if(r & 1)  add[r ^ 1] += x, sum[r ^ 1] += i * x, R += i;
    }
    sum[l] += L * x, sum[r] += R * x;
    while(l >>= 1) sum[l] += x * (L + R);
}

LL query(int l, int r) {
    l += M - 1, r += M + 1;
    LL ans = 0;
    int L = 0, R = 0;
    for (int i = 1; l ^ r ^ 1; i <<= 1, l >>= 1, r >>= 1) {
        ans += add[l] * L + add[r] * R;
        if(~l & 1) ans += sum[l ^ 1], L += i;
        if(r & 1)  ans += sum[r ^ 1], R += i;
    }
    ans += add[l] * L + add[r] * R;
    while(l >>= 1) ans += add[l] * (L + R);
    return ans;
}

int main() {
    scanf("%d", &n);
    build();
    int q;
    scanf("%d", &q);
    while(q--) {
        int op, a, b, c;
        scanf("%d%d%d", &op, &a, &b);
        if(op == 1) {
            scanf("%d", &c);
            update(a, b, c);
        }
        else
            printf("%lld\n", query(a, b));
    }
    return 0;
}

ZKW 线段树 的确比普通线段树要快一点,内存还小

ZKW :    总时间耗费: 661ms        总内存耗费: 7 MB

线段树 : 总时间耗费: 1059ms      总内存耗费: 13 MB

上一篇: codevs 1297

下一篇: VS Code-插件