POJ 3468

传送门 :

A Simple Problem with Integers

 


        区间修改 + 区间查询

You have N integers, A1A2, ... , AN. You need to deal with two kinds of operations. One type of operation is to add some given number to each number in a given interval. The other is to ask for the sum of numbers in a given interval.

Input

The first line contains two numbers N and Q. 1 ≤ N,Q ≤ 100000.
The second line contains N numbers, the initial values of A1A2, ... , AN. -1000000000 ≤ Ai ≤ 1000000000.
Each of the next Q lines represents an operation.
"C a b c" means adding c to each of AaAa+1, ... , Ab. -10000 ≤ c ≤ 10000.
"Q a b" means querying the sum of AaAa+1, ... , Ab.

Output

You need to answer all Q commands in order. One answer in a line.

Sample Input
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
Sample Output
4
55
9
15
Hint
The sums may exceed the range of 32-bit integers.

          心路历程。。我觉得一张图可以体现:

            


不停的改啊改啊。。。

最后才发现 是** 输入格式出错了 应该是 %lld  我弄成了  %d

当个教训吧

#include<iostream>
#include<cstdio>
using namespace std;
long long int n,m,op,x,y,val;
long long int ans;
struct Tree{
	int l;
	int r;
	long long int w;
	long long 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("%lld",&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("%lld%lld",&n,&m);
	build(1,1,n);
	while(m--)
	{
		char op;
		cin>>op;
		scanf("%lld%lld",&x,&y);
		if(op == 'C')
		{
			scanf("%lld",&val);
			add(1);
		}
		else {
			ans = 0;
			ask(1);
			printf("%lld\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);
    int q;
    scanf("%d", &q);
    build();
    while(q--){
        int  a, b, c;
        char op;
        cin>>op; 
        scanf("%d%d", &a, &b);
        if(op == 'C') {
            scanf("%d", &c);
            update(a, b, c);
        }
        else if(op == 'Q')
            printf("%lld\n", query(a, b));
    }
    return 0;
}

呼。。。终于在睡觉之前 AC 了!

感谢昌神!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值