UVA 12436 - Rip Van Winkle's Code(线段树)

UVA 12436 - Rip Van Winkle‘s Code

题目链接

题意:区间修改一个添加等差数列,一个把区间设为某个值,然后询问区间和

思路:关键在于等差数列的地方,线段树的每个结点添加一个首项和公差,由于等差数列加上一个等差数列还是一个等差数列,利用这个性质就可以进行维护了,注意set操作会覆盖掉等差数列的操作

代码:

#include <cstdio>
#include <cstring>

#define lson(x) ((x<<1)+1)
#define rson(x) ((x<<1)+2)

typedef long long ll;
const int N = 250005;
int n;

struct Node {
	ll l, r, a1, d, c, val;
	int setc;
} node[N * 4];

void build(ll l, ll r, int x = 0) {
	node[x].l = l; node[x].r = r;
	node[x].a1 = node[x].d = node[x].val = node[x].setc = 0;
	if (l == r) return;
	ll mid = (l + r) / 2;
	build(l, mid, lson(x));
	build(mid + 1, r, rson(x));
}

void pushup(int x) {
	node[x].val = node[lson(x)].val + node[rson(x)].val;
}

void pushdown(int x) {
	if (node[x].setc) {
		node[lson(x)].c = node[rson(x)].c = node[x].c;
		node[lson(x)].val = (node[lson(x)].r - node[lson(x)].l + 1) * node[x].c;
		node[rson(x)].val = (node[rson(x)].r - node[rson(x)].l + 1) * node[x].c;
		node[lson(x)].setc = node[rson(x)].setc = 1;
		node[lson(x)].a1 = node[lson(x)].d = node[rson(x)].a1 = node[rson(x)].d = 0;
		node[x].setc = 0;
	}
	node[lson(x)].a1 += node[x].a1;
	node[lson(x)].d += node[x].d;
	ll l = node[x].l, r = node[x].r;
	ll mid = (l + r) / 2;
	ll amid = node[x].a1 + node[x].d * (mid - l + 1);
	ll len1 = (mid - l + 1), len2 = (r - mid);
	node[lson(x)].val += node[x].a1 * len1 + len1 * (len1 - 1) / 2 * node[x].d;
	node[rson(x)].a1 += amid;
	node[rson(x)].d += node[x].d;
	node[rson(x)].val += amid * len2 + len2 * (len2 - 1) / 2 * node[x].d;
	node[x].a1 = node[x].d = 0;
}

void A(ll l, ll r, ll d, int x = 0) {
	if (node[x].l >= l && node[x].r <= r) {
		ll st = node[x].l - l + 1;
		if (d == -1) st = r - node[x].l + 1;
		node[x].a1 += st;
		node[x].d += d;
		ll len = node[x].r - node[x].l + 1;
		node[x].val += st * len + len * (len - 1) / 2 * d;
		return;
	}
	pushdown(x);
	ll mid = (node[x].l + node[x].r) / 2;
	if (l <= mid) A(l, r, d, lson(x));
	if (r > mid) A(l, r, d, rson(x));
	pushup(x);
}

void C(ll l, ll r, ll c, int x = 0) {
	if (node[x].l >= l && node[x].r <= r) {
		node[x].setc = 1;
		node[x].c = c;
		node[x].val = (node[x].r - node[x].l + 1) * c;
		node[x].a1 = node[x].d = 0;
		return;
	}
	pushdown(x);
	ll mid = (node[x].l + node[x].r) / 2;
	if (l <= mid) C(l, r, c, lson(x));
	if (r > mid) C(l, r, c, rson(x));
	pushup(x);
}

ll S(ll l, ll r, int x = 0) {
	if (node[x].l >= l && node[x].r <= r)
		return node[x].val;
	pushdown(x);
	ll mid = (node[x].l + node[x].r) / 2;
	ll ans = 0;
	if (l <= mid) ans += S(l, r, lson(x));
	if (r > mid) ans += S(l, r, rson(x));
	pushup(x);
	return ans;
}

int main() {
	while (~scanf("%d", &n)) {
		build(1, 250000);
		ll a, b, c;
		char Q[2];
		while (n--) {
			scanf("%s%lld%lld", Q, &a, &b);
			if (Q[0] == 'C') scanf("%lld", &c);
			if (Q[0] == 'A') A(a, b, 1);
			if (Q[0] == 'B') A(a, b, -1);
			if (Q[0] == 'C') C(a, b, c);
			if (Q[0] == 'S') printf("%lld\n", S(a, b));
		}
	}
	return 0;
}

UVA 12436 - Rip Van Winkle's Code(线段树)

时间: 2024-11-05 00:42:28

UVA 12436 - Rip Van Winkle's Code(线段树)的相关文章

uva 12436 - Rip Van Winkle&#39;s Code(线段树)

题目链接:uva 12436 - Rip Van Winkle's Code 题目大意:四种操作,操作见题目. 解题思路:即用线段树维护一个等差数列,因为一个等差加上一个等差还是一个等差数列,所以对于每个节点记录区 间左端的值,也就是首项,以及公差即可.因为还有一个S操作,所以要开一个标记记录区间值是否相同. #include <cstdio> #include <cstring> #include <algorithm> using namespace std; ty

Uva 12436 Rip Van Winkle&#39;s Code

Rip Van Winkle was fed up with everything except programming. One day he found a problem whichrequired to perform three types of update operations (A, B, C), and one query operation S over an arraydata[]. Initially all elements of data are equal to 0

Light OJ 1411 Rip Van Winkle`s Code 线段树成段更新

题目来源:Light OJ 1411 Rip Van Winkle`s Code 题意:3中操作 1种查询 求区间和 其中每次可以把一段区间从左到右加上1,2,3,...或者从右到左加上...3,2,1 或者把某个区间的数都置为v 思路:我是加了6个域 add是这段区间每个数都要加上add  add是这么来的 对与123456...这个等差数列 可能要分为2个区间 那么我就分成123和123 两个右边的等差数列每个数还应该加上3 所以右区间add加3 v是这个区间都要置为v 他的优先级最高 b是

UVA-12436 Rip Van Winkle&#39;s Code (线段树区间更新)

题目大意:一个数组,四种操作: long long data[250001]; void A( int st, int nd ) { for( int i = st; i <= nd; i++ ) data[i] = data[i] + (i - st + 1); } void B( int st, int nd ) { for( int i = st; i <= nd; i++ ) data[i] = data[i] + (nd - i + 1); } void C( int st, int

UVA 12436-Rip Van Winkle&#39;s Code(线段树的区间更新)

题意: long long data[250001]; void A( int st, int nd ) { for( int i = st; i \le nd; i++ ) data[i] = data[i] + (i - st + 1); } void B( int st, int nd ) { for( int i = st; i \le nd; i++ ) data[i] = data[i] + (nd - i + 1); } void C( int st, int nd, int x

uva 1400 - &quot;Ray, Pass me the dishes!&quot;(线段树)

题目链接:uva 1400 - "Ray, Pass me the dishes!" 题目大意:给定一个长度为n个整数序列,对m次询问作出回答,对于每次询问(a,b),找到两个下标x,y使得x到y的连续和为区间a,b中最大的连续和,如果存在多解优先x小,然后y小. 解题思路:线段树,对于每个节点维护三个线段值: max_sub:区间连续最大和 max_prefix:区间连续前缀最大和 max_suffix:区间连续后缀最大和 建树的过程维护三个值,查询时只需考虑左右子节点的max_su

Uva 1400 &quot;Ray, Pass me the dishes!&quot; ( 线段树 + 区间查询 )

Uva  1400 "Ray, Pass me the dishes!" (线段树 + 区间查询) 题意: 给顶一个长度为n的整数序列D,我们的任务是对m的询问做出回答对于询问(a,b),需要找到两个下标x和y,是的 a <= x <= y <=b并且Dx+...........Dy 尽量大. x,y尽量小 分析: 这题是做线段树比较好的一题,大白书上介绍的是维护了三个域,maxsub,maxpre,maxsuf这里也可以只维护两个域,再最后再考虑跨区间的问题这里没有

【UVA】11992 - Fast Matrix Operations(线段树模板)

基本的线段树,需要注意的是由于有set和add操作,懒惰标记下推的时候,优先递推set,之后递推add,每次执行set操作将add标记清0 WA了好几次是因为计算那一段的时候出问题了,可笑的是我对着模板找了一个多小时的错. #include<cstdio> #include<cmath> #include<queue> #include<stack> #include<map> #include<algorithm> using na

UVA 11134 - Fabled Rooks(贪心 / 二分图 + 线段树优化连边)

题目地址:Fabled Rooks 题目大意:n * n 的棋盘上摆了 n <=10^5 个车,让他们两两不攻击,每个车必须摆在一个给定矩形里,给出一个解决方案? 1. 贪心 由于行列互不影响, 所以可以分两遍求.第一遍确定每个车的行数,第二遍确定列数. 以行为例,若从左到右扫描,则按照区间的右端点升序排序,因为如果扫到一个位置两枚棋子都可以放,则选择右端点较小的那个(右端点大的后面还有机会). 2. 二分图匹配 有个毒瘤老师把题目改成了这样:n * n 的棋盘上摆了 n <=10^5 个车,