codeforces 1567E Non-Decreasing Dilemma (线段树)

题目链接:https://codeforces.com/contest/1567/problem/E

维护每个位置所在的连续不降序列的左端点 \(p[i]\),容易发现是单调不降的

答案就是 \(\frac{(l+r)\times(r-l+1)}{2}+(r-l+1)-\sum_l^r p[i]\)

修改操作分变化后高于/低于左边,高于/低于右边讨论即可

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int maxn = 200010;
const int INF = 1000000007;

int n, q;
int a[maxn], p[maxn];

struct Node{
	int mi, tag;
	ll sum;
}t[maxn<<2];

void pushup(int i){
	t[i].sum = t[i<<1].sum + t[i<<1|1].sum;
	t[i].mi = min(t[i<<1].mi, t[i<<1|1].mi);
}

void build(int i, int l, int r){
	t[i].tag = 0;
	if(l == r){
		t[i].mi = t[i].sum = p[l];
		return;
	}
	
	int mid = (l + r) >> 1;
	build(i<<1, l, mid); build(i<<1|1, mid+1, r); 
	pushup(i);
}

void pushdown(int i, int l, int r){
	if(t[i].tag){
		t[i<<1].tag = t[i<<1|1].tag = t[i].tag;
		t[i<<1].mi = t[i<<1|1].mi = t[i].tag;
		
		int mid = (l + r) >> 1;
		t[i<<1].sum = 1ll * (mid-l+1) * t[i].tag;
		t[i<<1|1].sum = 1ll * (r-mid) * t[i].tag;
		
		t[i].tag = 0;
	}
}

void modify(int i, int k, int l, int r, int x, int y){
	if(x <= l && r <= y){
		t[i].tag = k;
		t[i].sum = 1ll * (r-l+1) * k;
		t[i].mi = k;
		return;
	} 
	pushdown(i, l, r);
	int mid = (l + r) >> 1;
	if(x <= mid) modify(i<<1, k, l, mid, x, y);
	if(y > mid) modify(i<<1|1, k, mid+1, r, x, y);
	pushup(i);
}

ll qsum(int i, int l, int r, int x, int y){
	if(x <= l && r <= y) {
		return t[i].sum;
	}
	pushdown(i, l, r);
	
	int mid = (l + r) >> 1;
	ll res = 0;
	if(x <= mid) res += qsum(i<<1, l, mid, x, y);
	if(y > mid) res += qsum(i<<1|1, mid+1, r, x, y);
	return res;
}

int find(int i, int v, int p, int l, int r){
	if(l > r) return 0;
	if(l == r) return l;
	pushdown(i, l, r);
	int mid = (l + r) >> 1;
	
	int pos = -1;
	if(t[i<<1|1].mi <= v) pos = find(i<<1|1, v, p, mid+1, r);
	if(pos != -1) return pos;
	if(t[i<<1].mi <= v && p <= mid) pos = find(i<<1, v, p, l, mid);
	return pos;
}

int findl(int i, int v, int x, int y, int l, int r){
	if(l == r) return l;
	pushdown(i, l, r);
	int mid = (l + r) >> 1;
	
	int pos = -1;
	if(t[i<<1|1].mi < v && y > mid) pos = findl(i<<1|1, v, x, y, mid+1, r);
	if(pos != -1) return pos;
	if(t[i<<1].mi < v && x <= mid) pos = findl(i<<1, v, x, y, l, mid);
	return pos;
}

ll read(){ ll s = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar(); } while(ch >= '0' && ch <= '9'){ s = s * 10 + ch - '0'; ch = getchar(); } return s * f; }

int main(){
	n = read(), q = read();
	for(int i = 1 ; i <= n ; ++i) a[i] = read();
	a[0] = INF;
	a[n+1] = INF;
	
	p[1] = 1;
	for(int i = 2 ; i <= n ; ++i) {
		if(a[i] >= a[i-1]) p[i] = p[i-1];
		else p[i] = i;
	}

	build(1, 1, n);

	int op, l, r; 
	for(int i = 1 ; i <= q ; ++i){
		op = read(), l = read(), r = read();
		if(op == 1){
			a[l] = r;
			int tmp = qsum(1, 1, n, l, l);
			if(a[l] >= a[l-1]){
				int pp = qsum(1, 1, n, l-1, l-1); 
				modify(1, pp, 1, n, l, l);
			}
			else {
				modify(1, l, 1, n, l, l);
			}
			
			if(a[l] > a[l+1]) {
				int pos = find(1, tmp, l+1, 1, n);
				if(pos != -1){
					modify(1, l+1, 1, n, l+1, pos);
				}
			} else{
				int ps = qsum(1, 1, n, l+1, l+1);
				int pos = find(1, ps, l+1, 1, n);
				if(pos != -1){
					int pp = qsum(1, 1, n, l, l);
					modify(1, pp, 1, n, l+1, pos); 
				} 
			}
		} else{
			int pos = findl(1, l, l, r, 1, n);
			ll res = 1ll * (r - l + 1);
			if(pos != -1) res -= 1ll * l * (pos-l+1);
			res += 1ll * (l+r) * (r-l+1) / 2;
			res -= qsum(1, 1, n, (pos==-1)?l:pos+1, r);
			printf("%lld\n", res);
		}
	}
	
	return 0;
}
posted @ 2021-09-07 20:15  Tartarus_li  阅读(58)  评论(0编辑  收藏  举报