Luogu P5069 [Ynoi2015] 纵使日薄西山

一开始想用线段树维护, 然后发现太多细节了,QAQ.

我们 可以发现一个数可以被取到最大值, 那么直接把他删到0不会影响结果.

因为 两边的位置都不能能取到最大值并影响当前位置.

所以我们只需要知道有多少个位置取到最大值即可.

O ( m n log ⁡ n ) O(mn\log n) O(mnlogn) 的做法是 直接排序, 然后把两边覆盖…

对于一段单调序列, 显然取第一大, 第三大, …

所以我们可以用树状数组维护奇偶的前缀和.

然后修改一个位置最多对旁边两条链有影响, 我们只需要暴力把影响减去, 后面加回来即可.

对于链的存储, 我们用 s e t set set 存极值点即可.

感谢扶咕咕的博客!!!

int n, a[N];
ll ans;

struct BIT {
	ll c[N];
	void add(int x, int v) { for( ; x <= n; x += x & -x) c[x] += v; }
	ll ask(int x) { ll y = 0; while(x) y += c[x], x &= x - 1; return y;}
	ll ask(int l, int r) { return ask(r) - ask(l - 1);}
} c[2];
set<int> s;
#define ev(x) (!((x) & 1))

void check(int x) {
	if((a[x] > a[x - 1]) == (a[x] >= a[x + 1])) s.insert(x);
	else s.erase(x);
}

void calc(IT l, IT r, int v) {//重算l~r之间的答案 
	while(l != r) {
		auto t = r; t--;
		if(a[*t] < a[*r]) ans += v * c[*r & 1].ask(*t + 1, *r);
		else {
			ans += v * c[*t & 1].ask(*t + 1, *r - 1);
			auto p = r; p++;
			if(p == s.end()) p--;
			if(ev(*r - *t) && ev(*r - *p)) ans += v * a[*r];
		}
		r = t;
	}
	int x = *l;
	if(a[x] >= a[x + 1]) return ;
	if(s.begin() != l) l--;
	++r; if(ev(x - *l) && ev(x - *r)) ans += v * a[x];
}

void upd(int x)  {
	int y; qr(y);
	IT v = s.lower_bound(x), l = v, r = v; l--; r++;
	if(l != s.begin()) l--;
	if(r != s.end()) r++;
	if(r == s.end()) r--;
	calc(l, r, -1);
	c[x & 1].add(x, y - a[x]); a[x] = y;
	check(x); if(x > 1) check(x - 1); if(x < n) check(x + 1);
	calc(l, r, 1);
}

void solve() {
	qr(n); s.insert(0); s.insert(n + 1);
	FOR(i, n) upd(i);
	int x, m; qr(m); while(m--) qr(x), upd(x), pr2(ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值