2023.3.8日寄

2023.3.8 外培 Day 2 日寄

模拟赛

\(~~~~\) 总结:做不了,全tm是ynoi

After God

\(~~~~\) 好像是lxl没有公开的题,不写了。

P6780 [Ynoi2009] pmrllcsrms

题意

\(~~~~\) 给定常数 \(c\) 和长为 \(n\) 的数列,\(m\) 次操作:修改数列中某一项的值或者询问数列某个区间内长度不超过 \(c\) 的最大子段和。
\(~~~~\) \(1\leq n,m\leq 2\times 10^6\).

题解

\(~~~~\) 很自然地想到把数列分成若干长为 \(c\) 的块,然后来考虑可以怎么做。

\(~~~~\) 显然答案只会在最多两个块中间产生,那么对两种情况都进行一个讨论:

\(~~~~\) 如果答案只在一个块中产生,那么这就是一个朴素的维护区间最大子段和的问题,再把每个块的结果放到线段树上一起查询即可。

\(~~~~\) 着重来看答案在两个块中的情况:那么我们把两个块都拉下来:如果在第一个块中我们选择了一个距离左端点为 \(i\) 的点,那么第二个块中我们选择的点距离左端点应该有 \(<c-i\) ,那么倒过来也就是距离右端点 \(>i\) ,假设这个位置为 \(j\) ,那么就是要找两个位置 \(i>j\) 。并且记 \(a_i\) 为第一个块的后缀和,\(b_i\) 为第一个块的前缀和,那么 \(a_i+b_j\) 的和必须最大。很显然我们只需要在每个位置的块都维护两个序列即可。

\(~~~~\) 然后对于边角块的情况,我们发现两个块可能不能完全取完,具体来说需要分成四个部分:\(l'\)\(l\) 之后,则 \(r'\)\(l\) 对应的位置之前;\(l'\)\(r\) 对应位置之后,则 \(r'\)\(r\) 以前;\([l,l')\) 的最大子段和,\((r',r]\) 的最大子段和,以及和块间一样的取法。

\(~~~~\) 说起来好像挺简单的,那就放代码吧。

代码
查看代码
#include <bits/stdc++.h>
#define ll long long
#define PII pair<int,int>
#define mp(a,b) make_pair(a,b)
using namespace std;
template<typename T>void read(T &x)
{
    T f=1;x=0;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();}
    x*=f;
}
template<typename T>void print(T x) {
    if(x<0) putchar('-'),x=-x;
    if(x>9) print(x/10);
    putchar(x%10+'0');
}
int arr[2000005];
template<typename T>inline T Min(T AA,T BB){return AA>BB?BB:AA;}
template<typename T>inline T Max(T AA,T BB){return AA<BB?BB:AA;}
struct node1{
	ll L,R,Det,Sum;
	node1(){}
	node1(ll LL,ll RR,ll DD,ll SS){L=LL,R=RR,Det=DD,Sum=SS;}
};
inline node1 Merge(node1 a,node1 b){return node1(Max(a.L,a.Sum+b.L),Max(b.R,b.Sum+a.R),Max(Max(a.Det,b.Det),a.R+b.L),a.Sum+b.Sum);}
struct SegmentTree1{
	#define ls p<<1
	#define rs p<<1|1
	#define lson p<<1,l,mid
	#define rson p<<1|1,mid+1,r 
	node1 tr[8000005];
	inline void pushUp(int p){tr[p]=Merge(tr[ls],tr[rs]);}
	void Build(int p,int l,int r)
	{
		if(l==r){tr[p]=node1(arr[l],arr[l],arr[l],arr[l]);return;}
		int mid=(l+r)>>1;
		Build(lson); Build(rson);
		pushUp(p);
	}
	void Modify(int p,int l,int r,int aim,int Val)
	{
		if(l==r){tr[p]=node1(Val,Val,Val,Val);return;}
		int mid=(l+r)>>1;
		if(aim<=mid) Modify(lson,aim,Val);
		if(mid<aim)  Modify(rson,aim,Val);
		pushUp(p);
	}
	node1 Query(int p,int l,int r,int lx,int rx)
	{
		if(lx<=l&&r<=rx) return tr[p];
		int mid=(l+r)>>1;
		if(lx<=mid&&mid<rx) return Merge(Query(lson,lx,rx),Query(rson,lx,rx));
		if(lx<=mid) return Query(lson,lx,rx);
		return Query(rson,lx,rx); 
	}
	#undef ls
	#undef rs
	#undef lson
	#undef rson
}Seg1;
ll X[2000005],Y[2000005];
struct SegmentTree2{//查询块内/块间得最大值 
	#define ls p<<1
	#define rs p<<1|1
	#define lson p<<1,l,mid
	#define rson p<<1|1,mid+1,r 
	ll Maxn[8000005];
	inline void pushUp(int p){Maxn[p]=Max(Maxn[ls],Maxn[rs]);}
	void Build(int p,int l,int r)
	{
		if(l==r){Maxn[p]=X[l];return;}
		int mid=(l+r)>>1;
		Build(lson); Build(rson);
		pushUp(p);
	}
	void Modify(int p,int l,int r,int aim,ll Val)
	{
		if(l==r){Maxn[p]=Val;return;}
		int mid=(l+r)>>1;
		if(aim<=mid) Modify(lson,aim,Val);
		if(mid<aim)  Modify(rson,aim,Val);
		pushUp(p);
	}
	ll Query(int p,int l,int r,int lx,int rx)
	{
		if(lx<=l&&r<=rx) return Maxn[p];
		int mid=(l+r)>>1;
		if(lx<=mid&&mid<rx) return Max(Query(lson,lx,rx),Query(rson,lx,rx));
		if(lx<=mid) return Query(lson,lx,rx);
		return Query(rson,lx,rx);
	}
	#undef ls
	#undef rs
	#undef lson
	#undef rson
}Seg21,Seg22;
struct node3{
	ll L,R,Det,Tag1,Tag2;
	node3(){}
	node3(ll l,ll r,ll det,ll tag1,ll tag2){L=l,R=r,Det=det,Tag1=tag1,Tag2=tag2;}
};
inline node3 Merge(node3 a,node3 b){return node3(Max(a.L,b.L),Max(a.R,b.R),Max(a.L+b.R,Max(a.Det,b.Det)),0,0);}//合并写对!!! 
struct SegmentTree3{
	#define ls p<<1
	#define rs p<<1|1
	#define lson p<<1,l,mid
	#define rson p<<1|1,mid+1,r 
	vector <node3> tr;
	inline void pushUp(int p){tr[p]=Merge(tr[ls],tr[rs]);}
	void pushDown(int p)
	{
		if(tr[p].Tag1)
		{
			tr[ls].Tag1+=tr[p].Tag1; tr[ls].Det+=tr[p].Tag1; tr[ls].L+=tr[p].Tag1;
			tr[rs].Tag1+=tr[p].Tag1; tr[rs].Det+=tr[p].Tag1; tr[rs].L+=tr[p].Tag1;
			tr[p].Tag1=0;	
		}
		if(tr[p].Tag2)
		{
			tr[ls].Tag2+=tr[p].Tag2; tr[ls].Det+=tr[p].Tag2; tr[ls].R+=tr[p].Tag2;
			tr[rs].Tag2+=tr[p].Tag2; tr[rs].Det+=tr[p].Tag2; tr[rs].R+=tr[p].Tag2;
			tr[p].Tag2=0;
		}
	}
	void Build(int p,int l,int r)
	{
		if(l==r){tr[p].L=Y[l];tr[p].R=X[l];tr[p].Det=-1e18;return;}
		int mid=(l+r)>>1;
		Build(lson); Build(rson);
		pushUp(p);
	}
	void Modify1(int p,int l,int r,int lx,int rx,ll Val)
	{
		if(lx<=l&&r<=rx)
		{
			tr[p].Tag1+=Val;tr[p].L+=Val;tr[p].Det+=Val;
			return;
		}
		int mid=(l+r)>>1; pushDown(p);
		if(lx<=mid) Modify1(lson,lx,rx,Val);
		if(mid<rx)  Modify1(rson,lx,rx,Val);
		pushUp(p); 
	}
	void Modify2(int p,int l,int r,int lx,int rx,ll Val)
	{
		if(lx<=l&&r<=rx)
		{
			tr[p].Tag2+=Val; tr[p].R+=Val; tr[p].Det+=Val;
			return;
		}
		int mid=(l+r)>>1;pushDown(p);//不pushDown见祖宗 
		if(lx<=mid) Modify2(lson,lx,rx,Val);
		if(mid<rx)  Modify2(rson,lx,rx,Val);
		pushUp(p);
	}
	node3 Query(int p,int l,int r,int lx,int rx)
	{
		if(lx>rx) return node3(0,0,0,0,0);
		if(lx<=l&&r<=rx) return tr[p];
		int mid=(l+r)>>1; pushDown(p);
		if(lx<=mid&&mid<rx) return Merge(Query(lson,lx,rx),Query(rson,lx,rx));
		if(lx<=mid) return Query(lson,lx,rx);
		return Query(rson,lx,rx);
		pushUp(p);
	}
	#undef ls
	#undef rs
	#undef lson
	#undef rson
}Seg3[2000005];
int main() {
//	freopen("girl.in","r",stdin);
//	freopen("girl.out","w",stdout);
	int n,m,c;read(n);read(m);read(c);c=Min(c,n);
	for(int i=1;i<=n;i++) read(arr[i]);
	Seg1.Build(1,1,n);int Block=(n-1)/c;
	if(!Block)
	{
		for(int i=1,op,l,r;i<=m;i++)
		{
			read(op);read(l);read(r);
			if(op==1) Seg1.Modify(1,1,n,l,r);
			else printf("%lld\n",Max(Seg1.Query(1,1,n,l,r).Det,0ll));
		}
		return 0;
	}
	if(c==1)
	{
		for(int i=1;i<=n;i++) X[i]=arr[i];
		Seg21.Build(1,1,n);
		for(int i=1,op,l,r;i<=m;i++)
		{
			read(op);read(l);read(r);
			if(op==1) Seg21.Modify(1,1,n,l,r);
			else printf("%lld\n",Max(Seg21.Query(1,1,n,l,r),0ll));
		}
		return 0;
	}
	for(int i=0;i<Block;i++) Seg3[i].tr.resize(c<<2);
	for(int i=0,l,r;i<Block;i++)
	{
		l=i*c+1; r=l+c-1;
		ll Sum=0;
		for(int j=r;j>=l;j--) Sum+=arr[j],X[j]=Sum;
		Sum=0;
		for(int j=l+c;j<=r+c;j++) Sum+=arr[j],Y[j-c]=Sum;
		Seg3[i].Build(1,l,r);
	}
	for(int i=0,l,r;i<=Block;i++)
	{
		l=i*c+1; r=Min(l+c-1,n);
		ll Sum=0,Ans=0;
		for(int j=l;j<=r;j++)
		{
			Sum+=arr[j];
			if(Sum<0) Sum=0;
			Ans=Max(Ans,Sum);
		}
		X[i]=Ans;
	}
	Seg21.Build(1,0,Block);
	for(int i=0;i<Block;i++) X[i]=Seg3[i].tr[1].Det;
	Seg22.Build(1,0,Block-1);
	for(int qwq=1,op,l,r;qwq<=m;qwq++)
	{
		read(op);read(l);read(r);
		if(op==1)
		{
			int id=(l-1)/c;
			ll Del=r-arr[l]; arr[l]=r;
			Seg1.Modify(1,1,n,l,r);
			
			Seg21.Modify(1,0,Block,id,Seg1.Query(1,1,n,id*c+1,(id+1)*c).Det);
			
			if(id)//非第一块的修改都要涉及前一块 
			{
				int L1=(id-1)*c+1,R1=id*c;
				Seg3[id-1].Modify1(1,L1,R1,l-c,R1,Del);
				Seg22.Modify(1,0,Block-1,id-1,Seg3[id-1].tr[1].Det);
			}
			if(id!=Block)//涉及自己 
			{
				int L1=id*c+1,R1=(id+1)*c;
				Seg3[id].Modify2(1,L1,R1,L1,l,Del);
				Seg22.Modify(1,0,Block-1,id,Seg3[id].tr[1].Det);
			}
		}
		else
		{
			int Bl=(l-1)/c,Br=(r-1)/c;
			int L1=Bl*c+1,R1=(Bl+1)*c;
			int L2=(Br-1)*c+1,R2=Br*c;
			if(r-l+1<=c)
			{
				print(Max(0ll,Seg1.Query(1,1,n,l,r).Det));puts("");
				continue;
			}
			if(Bl+1==Br)
			{
				ll Ans=Max(Seg1.Query(1,1,n,l,l+c-1).Det,Seg1.Query(1,1,n,r-c+1,r).Det);
				Ans=Max(Ans,0ll);
				if(r-l!=c)
				{
					Ans=Max(Ans,Seg3[Bl].Query(1,L1,R1,L1,l).L+Seg3[Bl].Query(1,L1,R1,l+1,R1).R);
					Ans=Max(Ans,Seg3[Bl].Query(1,L1,R1,L1,r-c-1).L+Seg3[Bl].Query(1,L1,R1,r-c,R1).R);
					Ans=Max(Ans,Seg3[Bl].Query(1,L1,R1,l,r-c-1).Det);
				}
				print(Ans);puts("");
			}
			else
			{
				ll Ans=Max(Seg1.Query(1,1,n,l,l+c-1).Det,Seg1.Query(1,1,n,r-c+1,r).Det);
				Ans=max(Ans,0ll);
				node3 L=Seg3[Bl].Query(1,L1,R1,l+1,R1),R=Seg3[Br-1].Query(1,L2,R2,L2,r-c-1);
				Ans=Max(Ans,Seg3[Bl].Query(1,L1,R1,L1,l).L+L.R);
				Ans=max(Ans,Seg3[Br-1].Query(1,L2,R2,r-c,R2).R+R.L);
				Ans=Max(Ans,Max(L.Det,R.Det));
				Ans=Max(Ans,Seg21.Query(1,0,Block,Bl+1,Br-1));
				if(Bl+1<=Br-2) Ans=Max(Ans,Seg22.Query(1,0,Block-1,Bl+1,Br-2));
				print(Ans);puts("");
			}
		}
	}
	return 0;
}
/*
瑶草一何碧,春入武陵溪。溪上桃花无数,花上有黄鹂。我欲穿花寻路,直入白云深处,浩气展虹霓。只恐花深里,红露湿人衣。
坐玉石,欹玉枕。拂金徽。谪仙何处,无人伴我白螺杯。我为灵芝仙草,不为朱唇丹脸,长啸亦何为。醉舞下山去,明月逐人归。
*/

愚者之夜

\(~~~~\) 还是lxl没公开的题,不写了。


日记

\(~~~~\) 其实感觉lxl讲题还是有意义的,没有之前那么答辩了。

\(~~~~\) 但是我必须吐槽在这个饭食,tmd居然会有比重庆摆专的食堂还不如的饭菜吗?还一顿¥20,你咋不抢呢。

\(~~~~\) 所以今天教练就带出去出去加了个餐以避免被答辩装填的饭食,然后下图是战绩。我猜这应该是我最后一次以OIER的身份线下团建了。虽然但是怎么我洗了个澡然后现在22:48我就已经快饿晕过去了,洗澡真的这么帮助挨饿吗?

\(~~~~\) 吃完感觉什么都没吃,结果等会还要喝点玄麦降降火,涂药防痘痘……

\(~~~~\) 10号就回去当维批,运批和演批了,学校生活爷回来了/kk所以现在是时候下线背维词了。另外自己可以少洗很多衣服好诶。

posted @ 2023-03-08 22:51  Azazеl  阅读(36)  评论(0编辑  收藏  举报