Loading

题解 CF1136E 【Nastya Hasn't Written a Legend】

推销 膜 zhouakngyang 宝典

\(\color{black}{\texttt {z}}\color{red}{\texttt {houakngyang}}\) AK 完比赛让我来做这题,我做了1h,他1hAK,被他吊起来打。

作为目前洛谷和CF的最优解来写篇题解

题解

靠的就是灵光一现。。。

看完题,正常人都会 发现这个 \(k_i\) 怎么这么烦啊,好像啥都不能维护啊。修改到哪里啊,怎么没有单调性啊。

然后不死心,开始找各种数据结构来维护。time is passing,rank is falling......

注意到这个数列看起来有点可以二分的感觉,但是没有单调性。

灵光一现:不好维护就别维护呗,用前缀和抵消啊

\(s_n=\sum\limits_{i=2}^{n}k_i\) (注意,k的下标为了方便从 \(2\) 开始)

\(b_i=a_i-s_i\)

那么 \(a_{i+1}<a_i+k_i \Leftrightarrow b_{i+1}<b_i\)

所以 \(b\) 单调不降,否则就更新过去了

于是可以二分右端点,二分到最靠右(事实上这与题目有些出入,但是带个等号没影响)的满足 \(b_{i+1} \le b_i+x\)\(x\) 是加上的数)的位置 \(r\) ,在线段树上把 \([i,r]\) 内的数赋值为 \(b_i+k\) ,最后询问的时候输出:\([l,r]\) 的区间和加上 \(ss_r-ss_{l-1}\)\(ss_i=\sum\limits_{j=2}^{i}s_j\) (就是把减掉的前缀和加回去)

优化

最优解不可能只用上面的思路的啊。

上面那个东西二分套个线段树是 \(O(n\log^2n)\) 的。

非常显然的可以把线段树二分换成单只 \(\log\) 的线段树上查找,因为线段树本身就是二分数据结构。

具体来说,对于每个区间维护最小值。

  • 如果右区间的最小值小于要二分的 \(v\) ,那么往右区间走,因为一定更靠右切存在可行解
  • 否则往左区间走。

于是这道题就变成 \(O(n\log n)\) 的啦。

然后发现我是次优解。

忽然有了信心,加个火车头加个fread就最优解了。

#define int long long
#define N 100009
const int inf=1e18;
inline int rd() {
	int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)) {if(ch=='-')f=-1;ch=getchar();}
	while(isdigit(ch))x=x*10+(ch^48),ch=getchar();
	return x*f;
}
inline int rdc() {
	char ch=getchar();
	while(ch!='+'&&ch!='s')ch=getchar();
	return ch=='s';
}
int a[N],k[N],s[N],v[N],n,ss[N];
int val[N<<2],tag[N<<2],miv[N<<2];
#define lc (p<<1)
#define rc (p<<1|1)
void pushup(int p) {
	val[p]=val[lc]+val[rc],miv[p]=std::min(miv[lc],miv[rc]);
}
void build(int l,int r,int p) {
	tag[p]=inf;
	if(l==r)return val[p]=miv[p]=v[l],void();
	int mid=(l+r)>>1;
	build(l,mid,lc),build(mid+1,r,rc);
	pushup(p);
}
void pushdown(int p,int l,int r) {
	if(tag[p]==inf)return;
	int mid=(l+r)>>1;
	tag[lc]=tag[rc]=tag[p],
	miv[lc]=miv[rc]=tag[p],
	val[lc]=tag[p]*(mid-l+1),
	val[rc]=tag[p]*(r-mid),
	tag[p]=inf;
}
int query(int ql,int qr,int l,int r,int p) {
	if(ql<=l&&r<=qr)return val[p];
	pushdown(p,l,r);
	int mid=(l+r)>>1,res=0;
	if(ql<=mid)res+=query(ql,qr,l,mid,lc);
	if(mid<qr)res+=query(ql,qr,mid+1,r,rc);
	return res;
}
void update(int ql,int qr,int l,int r,int p,int k) {
	if(ql<=l&&r<=qr) {
		tag[p]=miv[p]=k,val[p]=k*(r-l+1);return;
	}
	pushdown(p,l,r);
	int mid=(l+r)>>1;
	if(ql<=mid)update(ql,qr,l,mid,lc,k);
	if(mid<qr)update(ql,qr,mid+1,r,rc,k);
	pushup(p);
}
int ask(int v,int l,int r,int p) {
	if(l==r)return l;
	pushdown(p,l,r);
	int mid=(l+r)>>1;
	if(miv[rc]<=v)return ask(v,mid+1,r,rc);
	else return ask(v,l,mid,lc);
}
signed main() {
	n=rd();
	for(int i=1;i<=n;++i)a[i]=rd();
	for(int i=2;i<=n;++i)k[i]=rd(),s[i]=s[i-1]+k[i],ss[i]=ss[i-1]+s[i];
	for(int i=1;i<=n;++i)v[i]=a[i]-s[i];
	build(1,n,1);
	for(int q=rd();q;--q) {
		int opt=rdc(),x=rd(),y=rd();
		if(opt)printf("%lld\n",query(x,y,1,n,1)+ss[y]-ss[x-1]);
		else {
			int now=query(x,x,1,n,1);
			update(x,ask(now+y,1,n,1),1,n,1,now+y);
		}
	}
	return 0;
}
posted @ 2020-09-08 18:58  zzctommy  阅读(157)  评论(0编辑  收藏  举报