hdu5306 Gorgeous Sequence

传送门
要求支持操作:区间取 m i n min min,区间求 m a x max max,区间求和。
m i n min min操作维护方式:记录一个最大值和最大值出现次数和次大值。
对于区间对 x x x m i n min min操作,当前递归到 r o o t root root节点。用 m a x max max记录最大值, s u b sub sub记录次大值。分类讨论:
x > = T [ r o o t ] . m a x x>=T[root].max x>=T[root].max直接返回。
T [ r o o t ] . s u b &lt; x &lt; T [ r o o t ] . m a x T[root].sub&lt;x&lt;T[root].max T[root].sub<x<T[root].max,现在只会将这些最大值改为 x x x,那么 s u m sum sum减少 T [ r o o t ] . c n t ∗ ( T [ r o o t ] . m a x − x ) T[root].cnt*(T[root].max-x) T[root].cnt(T[root].maxx)。其中 c n t cnt cnt为最大值出现次数。
x &lt; = T [ r o o t ] . s u b x&lt;=T[root].sub x<=T[root].sub,那么递归两个儿子继续做。
其实一个节点的 m a x max max也可以看做是一个对它子树取 m i n min min的标记。
然后稍微注意 p u s h u p pushup pushup p u s h d o w n pushdown pushdown即可。把叶子节点的次小值赋为 − 1 -1 1是保证在叶子节点的时候会返回,防止死循环。
复杂度是 O ( n l o g 2 n ) O(nlog^2n) O(nlog2n),不知道为什么,可能是由于某股神秘的东方力量。。?

#include<bits/stdc++.h>
#define mid (T[root].l+T[root].r>>1)
#define lc (root<<1)
#define rc (root<<1|1)
using namespace std;
typedef long long ll;
const int maxn=1e6+10;
int Case,n,m,op,l,r,x,a[maxn];
struct node{
	int l,r,mx,sb,cnt;
	ll sum;
}T[maxn<<2];
inline void pushup(int root){
	T[root].sum=T[lc].sum+T[rc].sum;
	T[root].mx=max(T[lc].mx,T[rc].mx);
	T[root].sb=max((T[lc].mx==T[root].mx)?T[lc].sb:T[lc].mx,(T[rc].mx==T[root].mx)?T[rc].sb:T[rc].mx);
	T[root].cnt=((T[lc].mx==T[root].mx)?T[lc].cnt:0)+((T[rc].mx==T[root].mx)?T[rc].cnt:0);
}
inline void build(int root,int l,int r){
	T[root].l=l,T[root].r=r;
	if(l==r){T[root].sum=T[root].mx=a[l],T[root].sb=-1,T[root].cnt=1;return;}
	build(lc,l,mid),build(rc,mid+1,r),pushup(root);
}
//val 取min 
inline void pushnow(int root,int val){
	if(val>=T[root].mx) return;
	T[root].sum+=1ll*T[root].cnt*(val-T[root].mx);
	T[root].mx=val;
}
inline void pushdown(int root){pushnow(lc,T[root].mx),pushnow(rc,T[root].mx);}
inline void minimize(int root,int l,int r,int val){
	if(val>=T[root].mx) return;
	if(l<=T[root].l&&T[root].r<=r&&val>T[root].sb)
		return pushnow(root,val);
	pushdown(root);
	if(l<=mid) minimize(lc,l,r,val);
	if(r> mid) minimize(rc,l,r,val);
	pushup(root);
}
inline ll getmax(int root,int l,int r){
	if(l<=T[root].l&&T[root].r<=r) return T[root].mx;
	pushdown(root);
	if(r<=mid) return getmax(lc,l,r);
	if(l> mid) return getmax(rc,l,r);
	return max(getmax(lc,l,r),getmax(rc,l,r));
}
inline ll getsum(int root,int l,int r){
	if(l<=T[root].l&&T[root].r<=r) return T[root].sum;
	pushdown(root);
	if(r<=mid) return getsum(lc,l,r);
	if(l> mid) return getsum(rc,l,r);
	return getsum(lc,l,r)+getsum(rc,l,r);
}
int main(){
	scanf("%d",&Case);
	while(Case--){
		scanf("%d%d",&n,&m);
		for(int i=1;i<=n;++i) scanf("%d",a+i);
		build(1,1,n);
		while(m--){
			scanf("%d%d%d",&op,&l,&r);
			if(op==0) scanf("%d",&x),minimize(1,l,r,x);
			if(op==1) printf("%lld\n",getmax(1,l,r));
			if(op==2) printf("%lld\n",getsum(1,l,r));
		}
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值