Loading

bzoj#4695 最假女选手 segment tree beats 多种操作

题意:
image

思路:
\(2,3\)操作其实就是区间的最值操作,类似于一个最值操作的维护过程,我们考虑维护最大值,次大值,最大值出现次数,最小值,次小值,最小值出现次数,加的懒标记,区间和
其实思路比较常规,就是代码量稍大点,容易写错,由于区间加减操作并不会对当前节点维护的区间最值和次最值产生影响,所以维护的时候,先操作加减的标记,然后就用子节点和父节点的最值大小关系来实时更新维护即可。

\(min\)标记和\(max\)标记其实在节点下推的过程中他们之间的先后顺序并不会对结果产生不同的影响,所以先下推那个标记均可。

细节就是在下推和更新最大值/最小值的时候,我么需要特殊的考虑另一个最值和当前最值存在相等的情况也要及时更新,即维护区间内只有一种数和只有两种数这种情况,需要特判处理一下。
因为其他的情况,假如我们对\(max\)标记进行更新,如果这个更新的值是比\(min\)还小,那么递归到叶子的话,\(min\)的值会在\(pushup\)回溯时完成更新。如果更新的\(max\)标记大于次大值,那么此时出去上文提到那两种特殊情况,次小值和最小值是一定不会被更新的,所以也就不用操作。那么对\(min\)标记进行操作时也是同理的情况。

#include <bits/stdc++.h>

using namespace std;

#define pb push_back
#define eb emplace_back
#define MP make_pair
#define pii pair<int,int>
#define pll pair<ll,ll>
#define lson rt<<1
#define rson rt<<1|1
#define CLOSE std::ios::sync_with_stdio(false)
#define sz(x) (int)(x).size()
typedef long long ll;
typedef double db;
const int INF = 0x3f3f3f3f;
const db eps = 1e-6;
const int N = 5e5 + 10;

int n,m;
int ma[N<<2],sema[N<<2],mi[N<<2],semi[N<<2],add[N<<2],a[N],macnt[N<<2],micnt[N<<2];
ll sum[N<<2];

void pushup(int rt) {
	sum[rt] = sum[lson] + sum[rson];
	ma[rt] = max(ma[lson],ma[rson]);
	mi[rt] = min(mi[lson],mi[rson]);
	if(ma[lson] == ma[rson]) {
		macnt[rt] = macnt[lson] + macnt[rson];
		sema[rt] = max(sema[lson],sema[rson]);
	}
	if(ma[lson] > ma[rson]) {
		macnt[rt] = macnt[lson];
		sema[rt] = max(sema[lson],ma[rson]);
	}
	if(ma[lson] < ma[rson]) {
		macnt[rt] = macnt[rson];
		sema[rt] = max(sema[rson],ma[lson]);
	}
	if(mi[lson] == mi[rson]) {
		micnt[rt] = micnt[lson] + micnt[rson];
		semi[rt] = min(semi[lson],semi[rson]);
	}
	if(mi[lson] < mi[rson]) {
		micnt[rt] = micnt[lson];
		semi[rt] = min(semi[lson],mi[rson]);
	}
	if(mi[lson] > mi[rson]) {
		micnt[rt] = micnt[rson];
		semi[rt] = min(semi[rson],mi[lson]);
	}
}

void pushdown(int rt,int tot) {
	if(add[rt]) {
		sum[lson] += 1ll * (tot - tot / 2) * add[rt];
		sum[rson] += 1ll * (tot / 2) * add[rt];
		add[lson] += add[rt];
		add[rson] += add[rt];
		ma[lson] += add[rt];
		ma[rson] += add[rt];
		sema[lson] += add[rt];
		sema[rson] += add[rt];
		mi[lson] += add[rt];
		mi[rson] += add[rt];
		semi[lson] += add[rt];
		semi[rson] += add[rt];
		add[rt] = 0;
	}

	if(ma[lson] > ma[rt]) {//区间只有一种值或者两种值的时候 要相应的更新最小值和次小值 其他情况对最大值和次小值没有影响或者会pushup回来
		if(mi[lson] == ma[lson]) mi[lson] = ma[rt];
		if(semi[lson] == ma[lson]) semi[lson] = ma[rt];
		sum[lson] -= 1ll * (ma[lson] - ma[rt]) * macnt[lson];
		ma[lson] = ma[rt];
	}
	if(ma[rson] > ma[rt]) {
		if(mi[rson] == ma[rson]) mi[rson] = ma[rt];
		if(semi[rson] == ma[rson]) semi[rson] = ma[rt];
		sum[rson] -= 1ll * (ma[rson] - ma[rt]) * macnt[rson];
		ma[rson] = ma[rt];
	}

	if(mi[lson] < mi[rt]) {
		if(ma[lson] == mi[lson]) ma[lson] = mi[rt];
		if(sema[lson] == mi[lson]) sema[lson] = mi[rt];
		sum[lson] += 1ll * (mi[rt] - mi[lson]) * micnt[lson];
		mi[lson] = mi[rt];
	}
	if(mi[rson] < mi[rt]) {
		if(ma[rson] == mi[rson]) ma[rson] = mi[rt];
		if(sema[rson] == mi[rson]) sema[rson] = mi[rt];
		sum[rson] += 1ll * (mi[rt] - mi[rson]) * micnt[rson];
		mi[rson] = mi[rt];
	}
}

void build(int rt,int l,int r) {
	if(l == r) {
		add[rt] = 0;
		sum[rt] = mi[rt] = ma[rt] = a[l];
		micnt[rt] = macnt[rt] = 1;
		sema[rt] = -INF;
		semi[rt] = INF;
		return ;
	}
	add[rt] = 0;
	int mid = (l + r) >> 1;
	build(lson,l,mid); build(rson,mid+1,r);
	pushup(rt);
}
void modify_add(int rt,int l,int r,int L,int R,int v) {
	if(l >= L && r <= R) {
		add[rt] += v;
		sum[rt] += 1ll * (r - l + 1) * v;
		ma[rt] += v;
		sema[rt] += v;
		mi[rt] += v;
		semi[rt] += v;
		return ;
	}
	int mid = (l + r) >> 1;
	pushdown(rt,r-l+1);
	if(L <= mid) modify_add(lson,l,mid,L,R,v);
	if(R > mid) modify_add(rson,mid+1,r,L,R,v);
	pushup(rt);
}
void modify_min(int rt,int l,int r,int L,int R,int v) {
	if(v >= ma[rt]) return ;
	if(l >= L && r <= R && v > sema[rt]) {
		if(mi[rt] == ma[rt]) mi[rt] = v;
		if(semi[rt] == ma[rt]) semi[rt] = v;
		sum[rt] -= 1ll * (ma[rt] - v) * macnt[rt];
		ma[rt] = v;
		return ;
	}
	int mid = (l + r) >> 1;
	pushdown(rt,r-l+1);
	if(L <= mid) modify_min(lson,l,mid,L,R,v);
	if(R > mid) modify_min(rson,mid+1,r,L,R,v);
	pushup(rt);
}
void modify_max(int rt,int l,int r,int L,int R,int v) {
	if(v <= mi[rt]) return ;
	if(l >= L && r <= R && v < semi[rt]) {
		if(ma[rt] == mi[rt]) ma[rt] = v;
		if(sema[rt] == mi[rt]) sema[rt] = v;
		sum[rt] += 1ll * (v - mi[rt]) * micnt[rt];
		mi[rt] = v;
		return ;
	}
	int mid = (l + r) >> 1;
	pushdown(rt,r-l+1);
	if(L <= mid) modify_max(lson,l,mid,L,R,v);
	if(R > mid) modify_max(rson,mid+1,r,L,R,v);
	pushup(rt);
}
int qma(int rt,int l,int r,int L,int R) {
	if(l >= L && r <= R) return ma[rt];
	int mid = (l + r) >> 1,ans = -INF;
	pushdown(rt,r-l+1);
	if(L <= mid) ans = max(ans,qma(lson,l,mid,L,R));
	if(R > mid) ans = max(ans,qma(rson,mid+1,r,L,R));
	return ans;
}
int qmi(int rt,int l,int r,int L,int R) {
	if(l >= L && r <= R) return mi[rt];
	int mid = (l + r) >> 1,ans = INF;
	pushdown(rt,r-l+1);
	if(L <= mid) ans = min(ans,qmi(lson,l,mid,L,R));
	if(R > mid) ans = min(ans,qmi(rson,mid+1,r,L,R));
	return ans;
}
ll qsum(int rt,int l,int r,int L,int R) {
	if(l >= L && r <= R) return sum[rt];
	int mid = (l + r) >> 1;ll ans = 0;
	pushdown(rt,r-l+1);
	if(L <= mid) ans += qsum(lson,l,mid,L,R);
	if(R > mid) ans += qsum(rson,mid+1,r,L,R);
	return ans;
}

void solve() {
	scanf("%d",&n);
	for(int i = 1;i <= n;i ++) {
		scanf("%d",&a[i]);
	}
	build(1,1,n);
	// cout << "-----\n";
	scanf("%d",&m);
	int op,l,r,x;
	while(m--) {
		scanf("%d",&op);
		if(op == 1) {
			scanf("%d%d%d",&l,&r,&x);
			modify_add(1,1,n,l,r,x);
		}
		else if(op == 2) {
			scanf("%d%d%d",&l,&r,&x);
			modify_max(1,1,n,l,r,x);
		}
		else if(op == 3) {
			scanf("%d%d%d",&l,&r,&x);
			modify_min(1,1,n,l,r,x);
		}
		else if(op == 4) {
			scanf("%d%d",&l,&r);
			ll ans = qsum(1,1,n,l,r);
			printf("%lld\n",ans);
		}
		else if(op == 5) {
			scanf("%d%d",&l,&r);
			int ans = qma(1,1,n,l,r);
			printf("%d\n",ans);
		}
		else if(op == 6) {
			scanf("%d%d",&l,&r);
			int ans = qmi(1,1,n,l,r);
			printf("%d\n",ans);
		}
	}
}

int main() {
	solve();
	return 0;
}
posted @ 2021-09-01 20:20  x7x7g7c7  阅读(81)  评论(0)    收藏  举报