首页 > 其他分享 >[Ynoi2015] 纵使日薄西山

[Ynoi2015] 纵使日薄西山

时间:2023-02-08 06:55:16浏览次数:65  
标签:纵使 cp return int Ynoi2015 ret 日薄西山 include define

题传

考虑一个 \(a_i\) 变为最大值的时候,由于它与两边的值相对大小不变,因此 \(a_i\) 造成的贡献必然是它自己,进一步地,题目操作可以简化为每次选择一个靠左地最大值,将其和左右删除,删除代价为最大值。

考虑最终是哪些值作为最大值被删除,手摸一会样例,将最终选出来的序列拆分成若干个单调序列,发现奇偶性是相同的(因为每删除一个值就会将两边奇偶性不同的删除),注意单调序列之间的位置要小分讨,计算贡献时把每个单调队列的头塞入 set 中,这样就珂以快速计算贡献了。

对于单点修改,首先其自身和其前后形成的单调序列的方向会改变,注意相邻两位的贡献都会因为序列的方向而贡献产生变化,拿个树状数组记录前缀和即可,

复杂度 \(O(n\log n)\)。

Code:

#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <cctype>
#include <vector>
#include <queue>
#include <bitset>
#include <set>
#define vi vector<int>
#define pb push_back
#define mp make_pair
#define st first
#define nd second
#define int long long
using namespace std;
typedef long long ll;
typedef pair <int, int> Pii;
const int INF=0x3f3f3f3f;
const int cp=1e9+7;
inline int plust(int x, int y){x+=y;if(x>=cp) x-=cp;if(x<0) x+=cp;return x;}
inline int minut(int x, int y){x-=y;if(x>=cp) x-=cp;if(x<0) x+=cp;return x;}
inline int read(){
	char ch=getchar();int x=0, f=1;
	while(!isdigit(ch)){if(ch=='-') f=-1; ch=getchar();}
	while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
	return x*f;
}
inline void write(int x){
    if(x<0) putchar('-'), x=-x;
    if(x>9) write(x/10);
    putchar(x%10+'0');
}
inline int ksm(int a, int b=cp-2){
	int ret=1;
	for(; b; b>>=1, a=1ll*a*a%cp)
		if(b&1) ret=1ll*ret*a%cp;
	return ret;
}
const int N=1e5+5;
int n, m, a[N];
set <int> S;
set <int> :: iterator l, r;
#define lowbit(x) (x&(-x))
int bit[2][N];
void add(int op, int x, int v){for(; x<=n; x+=lowbit(x)) bit[op][x]+=v;}
int query(int op, int x, int t=0){for(; x; x-=lowbit(x)) t+=bit[op][x];return t;}
int rangeQ(int op, int l, int r){return query(op, r)-query(op, l-1);}
#undef lowbit
bool checkin(int x){return (a[x-1]<a[x]&&a[x]>=a[x+1])||(a[x-1]>=a[x]&&a[x]<a[x+1]);}
ll ans;
ll value(int x){
	if(S.find(x)==S.end()||x<1||x>n) return 0;
	if(x==1){int nxt=*S.upper_bound(x);return a[x]<a[nxt]?query(nxt&1, nxt-1):0;}
	if(x==n){int lst=*(--S.lower_bound(x));return a[x]<=a[lst]?rangeQ(lst&1, lst, x):a[x];}
	int lst=*(--S.lower_bound(x)), nxt=*S.upper_bound(x);
	if(a[x]<=a[lst]&&a[x]<a[nxt]){
		int tmp=rangeQ(lst&1, lst, x-1)+rangeQ(nxt&1, x+1, nxt-1);
		return ((x&1)==(lst&1)&&(x&1)==(nxt&1))?(tmp+a[x]):tmp;
    }
    return 0;
}
signed main(){
	n=read();
	for(int i=1; i<=n; ++i) a[i]=read(), add(i&1, i, a[i]);
	S.insert(0), S.insert(1), S.insert(-1), S.insert(-2);
	S.insert(n), S.insert(n+1), S.insert(n+2), S.insert(n+3);
	for(int i=2; i<n; ++i) if(checkin(i)) S.insert(i);
	for(auto v:S) ans+=value(v);
	m=read();
	for(int i=1; i<=m; ++i){
		int x=read(), y=read();ans-=value(x);
        l=S.lower_bound(x);r=S.upper_bound(x);
        l--;ans-=value(*l)+value(*r);
        l--, r++;ans-=value(*l)+value(*r);
        S.erase(x);S.erase(x-1);S.erase(x+1);
		add(x&1, x, -a[x]), a[x]=y, add(x&1, x, a[x]);
		for(int j=x-1; j<=x+1; ++j)
			if((j>1&&j<n)&&checkin(j)) S.insert(j);
			else if(j<=1||j>=n) S.insert(j);
		while(l!=r) ans+=value(*l), ++l;
        ans+=value(*r);
		printf("%lld\n", ans);
	}
	return 0;
}




标签:纵使,cp,return,int,Ynoi2015,ret,日薄西山,include,define
From: https://www.cnblogs.com/sizeof127/p/17100370.html

相关文章

  • 2021 年终总结|纵使前方不易,独善其身,继续前行。。。
    序言害,最怕的就是年中、年终总结,似乎又是一个忙忙碌碌而又碌碌无为的一年。不过也好,总算是正视过去的一年,吸取经验教训,为了日后做一些规划。好的一点,敢于面对了。其实是舔着......
  • [Ynoi2015] 盼君勿忘
    题传世纪诈骗题首先,所有子序列分别去重的和的意思是什么?令可重集\(S\)为序列\(a_l,a_{l+1}\dotsa_r\)的所有子序契合。假设我们有一个序列\(T\),对\(T\)去重......
  • [Ynoi2015] 此时此刻的光辉
    题传做完CF1422F再做这道题就肥肠有感觉了。如果你不想再看一题那么我就无耻推销一下我的题解。\[\text{————————我是分割线————————}\]请确保你......
  • [Ynoi2015] 我回来了
    题传7个月后再来看这道题,还是感觉太妙了。由于答案最终输出\(E\timesLen\),所以本质上是问\(\foralld\in[L,R]\)的贡献和,再进一步想,亵渎的要求就是寻找序列\[x_......
  • [Ynoi2015] 即便看不到未来
    题传\(O(10n\logn)\)能过,居然不卡常,青结了。感觉是比较套路的一道Ynoi了qwq。首先看题目,需要找的就是一段长度为\(1\dots10\)的极长连续的(公差为1)的等差数......