hdu4348 To the moon

题面在这里

题目大意:

给一个序列,4种操作:

  1. C l r x    时间戳++,并把[l, r]区间内的数都加一。
  2. Q l r       询问当前时间戳的[l, r]区间和。
  3. H l r x    询问x时间戳的[l, r]区间和。
  4. B x        将当前时间戳更改为x。

做法:

做法就是主席树,每次更改的时候新建一颗线段树,并且维护一个lazy tag即可。


/*************************************************************
	Problem: hdu 4348 To the moon
	User: fengyuan
	Language: C++
	Result: Accepted
	Time: 280 ms
	Memory: 56.4 MB
	Submit_Time: 2017-12-03 17:26:22
*************************************************************/

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cctype>
#include<vector>
#include<map>
#include<queue>
#define rep(i, x, y) for (int i = (x); i <= (y); i ++)
#define down(i, x, y) for (int i = (x); i >= (y); i --)
#define mid ((l+r)/2)
#define lc (o<<1)
#define rc (o<<1|1)
#define pb push_back
#define mp make_pair
#define PII pair<int, int>
#define F first
#define S second
#define B begin()
#define E end()
using namespace std;
typedef long long LL;
//head

const int N = 100005, M = 3000010;
int n, m, tot, clk;
int a[N], T[N], L[M], R[M], add[M];
LL sum[M];

inline void pushup(int rt)
{
	sum[rt] = sum[L[rt]] + sum[R[rt]];
}

inline int build(int l, int r)
{
	int rt = ++ tot;
	if (l == r){
		L[rt] = 0; R[rt] = 0;
		sum[rt] = a[l];
		return rt;
	}
	L[rt] = build(l, mid);
	R[rt] = build(mid+1, r);
	pushup(rt);
	return rt;
}

inline int insert(int pre, int l, int r, int x, int y, int w)
{
	int rt = ++ tot;
	L[rt] = L[pre]; R[rt] = R[pre]; add[rt] = add[pre]; sum[rt] = sum[pre];
	sum[rt] += 1LL*w*(y-x+1);
	if (l == x && r == y){
		add[rt] += w;
		return rt;
	}
	if (y <= mid) L[rt] = insert(L[pre], l, mid, x, y, w);
	else if (x > mid) R[rt] = insert(R[pre], mid+1, r, x, y, w);
	else L[rt] = insert(L[pre], l, mid, x, mid, w), R[rt] = insert(R[pre], mid+1, r, mid+1, y, w);
	return rt;
}

inline LL query(int o, int l, int r, int x, int y)
{
	if (l == x && r == y) return sum[o];
	LL ret = 1LL*add[o]*(y-x+1);
	if (y <= mid) return ret + query(L[o], l, mid, x, y);
	else if (x > mid) return ret + query(R[o], mid+1, r, x, y);
	else return ret + query(L[o], l, mid, x, mid) + query(R[o], mid+1, r, mid+1, y);
}

int main()
{
	bool flag = false;
	while (~scanf("%d%d", &n, &m)){
		if (flag) puts("");
		flag = true;
		rep(i, 1, n) scanf("%d", &a[i]);
		tot = 0;
		memset(T, 0, sizeof T);
		memset(sum, 0, sizeof sum);
		memset(add, 0, sizeof add);
		T[0] = build(1, n); clk = 0;
		while (m --){
			char ch[3]; int l, r, x;
			scanf("%s", ch);
			if (ch[0] == 'C'){
				scanf("%d%d%d", &l, &r, &x);
				clk ++;
				T[clk] = insert(T[clk-1], 1, n, l, r, x);
			} else if (ch[0] == 'Q'){
				scanf("%d%d", &l, &r);
				printf("%lld\n", query(T[clk], 1, n, l, r));
			} else if (ch[0] == 'H'){
				scanf("%d%d%d", &l, &r, &x);
				printf("%lld\n", query(T[x], 1, n, l, r));
			} else scanf("%d", &clk);
		}
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值