势能线段树

Segment tree Beats

待完善。

#include <cstdio>
#include <cctype>
#include <algorithm>
#pragma GCC diagnostic error "-std=gnu++11"
#define reg register
using namespace std;

namespace fast_IO {
	template <typename conv>
	inline conv read(conv &x) {
		char ch=getchar(); int flag=1; x=0;
		while (!isdigit(ch)) {if (ch=='-') flag=-flag; ch=getchar();}
		while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-48; ch=getchar();}
		x*=flag;
	}
	template <typename conv, typename ... Args>
	inline conv read(conv &first, Args & ... args) {
		read(first);
		read(args...);
	}
	
	template <typename conv>
	inline conv write(conv x) {
		if (x<0) {putchar('-'); x=-x;}
		if (x>9) {write(x/10);}
		putchar(x%10+48);
	}
	template <typename conv, typename ... Args>
	inline conv write(conv first, Args ... args) {
		write(first);
		write(args...);
	}
}
using namespace fast_IO;

const int maxn=1e6+5, inf=1<<30;
int n, m;
int a[maxn];
struct segment {
	int left, right, length;
	int sum;
	int max, second_max, times_max;
	/*maximum, second maximum & the number of times the minimum occurs*/
	int min, second_min, times_min;
	/*minimum, second minimum & the number of times the minimum occurs*/
	int tag; /*addition*/
	#define len length
	#define nd_max second_max
	#define nd_min second_min
	#define T_max times_max
	#define T_min times_min
} tree[maxn<<2];

#define L left
#define R right
#define L_son left_son
#define R_son right_son
#define mid middle
#define val value
#define res result

void push_up(int now) {
	int left_son=now*2, right_son=now*2+1;
	tree[now].T_max=tree[now].T_min=0;
	tree[now].sum=tree[L_son].sum+tree[R_son].sum;
	
	tree[now].max=max(tree[L_son].max, tree[R_son].max);
	tree[now].nd_max=max(tree[L_son].nd_max, tree[R_son].nd_max);
	if (tree[L_son].max^tree[R_son].max) {
		tree[now].nd_max=max(tree[now].nd_max, min(tree[L_son].max, tree[R_son].max));
	}
	if (tree[now].max==tree[L_son].max) {
		tree[now].T_max+=tree[L_son].T_max;
	}
	if (tree[now].max==tree[R_son].max) {
		tree[now].T_max+=tree[R_son].T_max;
	}
	
	tree[now].min=min(tree[L_son].min, tree[R_son].min);
	tree[now].nd_min=min(tree[L_son].nd_min, tree[R_son].nd_min);
	if (tree[L_son].min^tree[R_son].min) {
		tree[now].nd_min=min(tree[now].nd_min, max(tree[L_son].min, tree[R_son].min));
	}
	if (tree[now].min==tree[L_son].min) {
		tree[now].T_min+=tree[L_son].T_min;
	}
	if (tree[now].min==tree[R_son].min) {
		tree[now].T_min+=tree[R_son].T_min;
	}
}

void build(int now, int left, int right) {
	tree[now].L=L; tree[now].R=R; tree[now].len=R-L+1;
	
	if (L==R) {
		tree[now].max=tree[now].min=tree[now].sum=a[L];
		tree[now].T_max=tree[now].T_min=1;
		tree[now].nd_max=-inf; tree[now].nd_min=inf;
		
		return ;
	}
	
	int middle=(L+R)>>1;
	int left_son=now*2 , right_son=now*2+1;
	build(L_son, L, mid); build(R_son, mid+1, R);
	
	push_up(now);
}

void push_down(int now) {
	int lazy_tag=tree[now].tag;
	tree[now].tag=0;
	
	int left_son=now*2 , right_son=now*2+1;
	if (lazy_tag) {
		tree[L_son].sum+=tree[L_son].len*lazy_tag;
		tree[L_son].tag+=lazy_tag;
		if (tree[L_son].nd_max>-inf) {
			tree[L_son].nd_max+=lazy_tag;
		}
		if (tree[L_son].nd_min<inf) {
			tree[L_son].nd_min+=lazy_tag;
		}
		
		tree[R_son].sum+=tree[R_son].len*lazy_tag;
		tree[R_son].tag+=lazy_tag;
		if (tree[R_son].nd_max>-inf) {
			tree[R_son].nd_max+=lazy_tag;
		}
		if (tree[R_son].nd_min<inf) {
			tree[R_son].nd_min+=lazy_tag;
		}
	}
	
	if (tree[L_son].min<tree[now].min && tree[now].min<tree[L_son].nd_min) {
		tree[L_son].sum+=(tree[now].min-tree[L_son].min)*tree[L_son].T_min;
		tree[L_son].min=tree[now].min;
		tree[L_son].max=max(tree[now].min, tree[L_son].max);
		if (tree[L_son].max==tree[L_son].min) {
			tree[L_son].sum=tree[L_son].len*tree[now].min;
			tree[L_son].T_min=tree[L_son].T_max=tree[L_son].len;
			tree[L_son].nd_max=-inf; tree[L_son].nd_min=inf;
		}
		else {
			tree[L_son].nd_max=max(tree[now].min, tree[L_son].nd_max);
		}
	}
	
	if (tree[R_son].min<tree[now].min && tree[now].min<tree[R_son].nd_min) {
		tree[R_son].sum+=(tree[now].min-tree[R_son].min)*tree[R_son].T_min;
		tree[R_son].min=tree[now].min;
		tree[R_son].max=max(tree[now].min, tree[R_son].max);
		if (tree[R_son].max==tree[R_son].min) {
			tree[R_son].sum=tree[R_son].len*tree[now].min;
			tree[R_son].T_min=tree[R_son].T_max=tree[R_son].len;
			tree[R_son].nd_max=-inf; tree[R_son].nd_min=inf;
		}
		else {
			tree[R_son].nd_max=max(tree[now].min, tree[R_son].nd_max);
		}
	}
	
	if (tree[L_son].nd_max<tree[now].max && tree[now].max<tree[L_son].max) {
		tree[L_son].sum+=(tree[now].max-tree[L_son].max)*tree[L_son].T_max;
		tree[L_son].max=tree[now].max;
		tree[L_son].min=min(tree[now].max, tree[L_son].min);
		if (tree[L_son].max==tree[L_son].min){
			tree[L_son].sum=tree[L_son].len*tree[now].max;
			tree[L_son].T_min=tree[L_son].T_max=tree[L_son].len;
			tree[L_son].nd_max=-inf; tree[L_son].nd_min=inf;
		}
		else {
			tree[L_son].nd_min=min(tree[now].max, tree[L_son].nd_min);
		}
	}
	
	if (tree[R_son].nd_max<tree[now].max && tree[now].max<tree[R_son].max) {
		tree[R_son].sum+=(tree[now].max-tree[R_son].max)*tree[R_son].T_max;
		tree[R_son].max=tree[now].max;
		tree[R_son].min=min(tree[now].max, tree[R_son].min);
		if (tree[R_son].max==tree[R_son].min){
			tree[R_son].sum=tree[R_son].len*tree[now].max;
			tree[R_son].T_min=tree[R_son].T_max=tree[R_son].len;
			tree[R_son].nd_max=-inf; tree[R_son].nd_min=inf;
		}
		else {
			tree[R_son].nd_min=min(tree[now].max, tree[R_son].nd_min);
		}
	}
}

void maximize(int now, int left, int right, int value) {
	if (tree[now].min>=val) {
		return ;
	}
	if (L<=tree[now].L && tree[now].R<=R && val<tree[now].nd_min) {
		tree[now].sum+=(val-tree[now].min)*tree[now].T_min;
		tree[now].min=val;
		tree[now].max=max(val, tree[now].max);
		if (tree[now].max==tree[now].min) {
			tree[now].sum=tree[now].len*val;
			tree[now].T_min=tree[now].T_max=tree[now].len;
			tree[now].nd_max=-inf; tree[now].nd_min=inf;
		}
		else {
			tree[now].nd_max=max(val, tree[now].nd_max);
		}
		
		return ;
	}
	
	int middle=(tree[now].L+tree[now].R)>>1;
	
	push_down(now);
	
	int left_son=now*2 , right_son=now*2+1;
	if (L<=mid) maximize(L_son, L, R, val);
	if (R>mid) maximize(R_son, L, R, val);
	
	push_up(now);
}

void minimize(int now, int left, int right, int value) {
	if (tree[now].min>=val) {
		return ;
	}
	if (L<=tree[now].L && tree[now].R<=R && val>tree[now].nd_max) {
		tree[now].sum+=(val-tree[now].max)*tree[now].T_max;
		tree[now].max=val;
		tree[now].min=min(val, tree[now].min);
		if (tree[now].max==tree[now].min){
			tree[now].sum=tree[now].len*val;
			tree[now].T_min=tree[now].T_max=tree[now].len;
			tree[now].nd_max=-inf; tree[now].nd_min=inf;
		}
		else {
			tree[now].nd_min=min(val, tree[now].nd_min);
		}
		
		return ;
	}
	
	int middle=(tree[now].L+tree[now].R)>>1;
	
	push_down(now);
	
	int left_son=now*2 , right_son=now*2+1;
	if (L<=mid) minimize(L_son, L, R, val);
	if (R>mid) minimize(R_son, L, R, val);
	
	push_up(now);
}

void update(int now, int left, int right, int value){
	if (!val) {
		return ;
	}
	if (L<=tree[now].L && tree[now].R<=R) {
		tree[now].sum+=tree[now].len*val;
		tree[now].tag+=val;
		tree[now].max+=val; tree[now].min+=val;
		if (tree[now].nd_max>-inf) {
			tree[now].nd_max+=val;
		}
		if (tree[now].nd_min<inf) {
			tree[now].nd_min+=val;
		}
		
		return ;
	}
	
	int middle=(tree[now].L+tree[now].R)>>1;
	
	push_down(now);
	
	int left_son=now*2 , right_son=now*2+1;
	if (L<=mid) {
		update(L_son, L, R, val);
	}
	if (R>mid) {
		update(R_son, L, R, val);
	}
	
	push_up(now);
}

int query(int now, int left, int right, int op) {
	if (L<=tree[now].L && tree[now].R<=R){
		if (op==4) {
			return tree[now].sum;
		}
		else if (op==5) {
			return tree[now].max;
		}
		else {
			return tree[now].min;
		}
	}
	
	int middle=(tree[now].L+tree[now].R)>>1;
	int result=0;
	
	push_down(now);
	
	int left_son=now*2 , right_son=now*2+1;
	if (op==4) {
		if (L<=mid) {
			res+=query(L_son, L, R, op);
		}
		if (R>mid) {
			res+=query(R_son, L, R, op);
		}
	}
	else if (op==5) {
		res=-inf;
		if (L<=mid) {
			res=max(res, query(L_son, L, R, op));
		}
		if (R>mid) {
			res=max(res, query(R_son, L, R, op));
		}
	}
	else {
		res=inf;
		if (L<=mid) {
			res=min(res, query(L_son, L, R, op));
		}
		if (R>mid) {
			res=min(res, query(R_son, L, R, op));
		}
	}
	
	push_up(now);
	
	return res;
}

int main() {
	read(n);
	for (reg int i=1; i<=n; i++) read(a[i]);
	build(1, 1, n);
	read(m);
	for (reg int i=1; i<=m; i++) {
		int op, x, y, z;
		read(op, x, y);
		if (op<=3) {
			read(z);
			if (op==1) {
				update(1, x, y, z);
			}
			if (op==2) {
				maximize(1, x, y, z);
			}
			if (op==3) {
				minimize(1, x, y, z);
			}
		}
		else {
			write(query(1, x, y, op)); putchar('\n');
		}
	}
	
	return 0;
}
posted @ 2020-08-07 22:29  willbe233  阅读(56)  评论(0)    收藏  举报