RE求助
查看原帖
RE求助
161296
DarksideCoderω楼主2020/9/16 20:29

思路和代码来源于 @ClCN

#include<cstdio>
#include<cstring>
#include<algorithm>
const long long Inf=0x3f3f3f3f3f3f3f3f;
struct Point
{
	long long x,y;
	Point(long long x=0,long long y=0):x(x),y(y){}
	inline friend Point operator+(const Point& a,const Point& b){return Point(a.x+b.x,a.y+b.y);}
	inline friend Point operator-(const Point& a,const Point& b){return Point(a.x-b.x,a.y-b.y);}
	inline friend long long Cross(const Point& a,const Point& b){return a.x*b.y-a.y*b.x;}
};
Point pool[20010000];
int pooltop;
Point* Allocate(int size)
{
	int tmp=pooltop;
	pooltop+=size;
	return pool+pooltop;
}
long long tag;
struct Hull
{
	Hull(){best=0;}
	Point* Data;
	int best,size;
	inline Point operator[](const int& x){return Data[x];}
	inline void Insert(const Point& x){Data[x.x].y=std::max(Data[x.x].y,x.y);}
	inline void PushBack(const Point& x){Data[size++]=x;}
	inline void Clean(const int& cnt)
	{
		Data[0]=Point(0,0);
		for(register int i=1;i<=cnt;i++)Data[i]=Point(i,-Inf);
		size=cnt+1;
	}
	inline void Convex()
	{
		if(size<=2)return;
		register int top=1;
		for(register int i=2;i<size;i++)
		{
			if(Data[i].y==-Inf)continue;
			while(top&&Cross(Data[top]-Data[top-1],Data[i]-Data[top-1])>=0)top--;
			Data[++top]=Data[i];
		}
		size=top+1;
	}
	inline long long MaxVal()
	{
		while(best+1<size&&(Data[best+1].x-Data[best].x)*tag+Data[best+1].y-Data[best].y>0)best++;
		return Data[best].x*tag+Data[best].y;
	}
	inline friend void Merge(Hull& c,Hull& a,Hull& b)
	{
		register int i=0,j=0,sizea=a.size,sizeb=b.size;
		c.Insert(a[i]+b[j]);
		while(i+1<sizea&&j+1<sizeb)
		{
			if(Cross(a[i+1]-a[i],b[j+1]-b[j])>=0)
				j++,c.Insert(a[i]+b[j]);
			else
				j++,c.Insert(a[i]+b[j]);
		}
		while(i+1<sizea)i++,c.Insert(a[i]+b[j]);
		while(j+1<sizeb)j++,c.Insert(a[i]+b[j]);
	}
};
struct Result
{
	long long data[2],ans,sum;
	Result(long long data1=0,long long data2=0,long long ans=0,long long sum=0)
		:ans(ans),sum(sum){data[0]=data1;data[1]=data2;}
	inline friend Result Merge(const Result& a,const Result& b)
		{return Result(std::max(a.data[0],a.sum+b.data[0]),std::max(b.data[1],b.sum+a.data[1]),std::max(std::max(a.ans,b.ans),a.data[1]+b.data[0]),a.sum+b.sum);}
};
long long Arr[310000];
const int MaxCnt=310000;
/*
       O
     /  \
    O   O
    
*/
struct Segment_Tree
{
	Segment_Tree(){Clean();}
	int cnt;
	int Son[MaxCnt<<2][2],Left[MaxCnt<<2],Right[MaxCnt<<2];
	Hull Data[MaxCnt<<2][2],Ans[MaxCnt<<2];
	long long Sum[MaxCnt<<1];
	inline void Clean(){cnt=0;}
	inline void MergeLeftRight(Hull& c,Hull& a,Hull& b,Point addtag)
	{
		register int sizea=a.size,sizeb=b.size;
		for(register int i=0;i<sizea;i++)c.PushBack(a[i]);
		for(register int i=0;i<sizeb;i++)c.PushBack(b[i]+addtag);
		c.Convex();
	}
	inline void PushUp(int now)
	{
		Ans[now].Clean(Right[now]-Left[now]+1);
		register int size;
		size=Ans[Son[now][0]].size;
		for(int i=0;i<size;i++)Ans[now].Insert(Ans[Son[now][0]][i]);
		size=Ans[Son[now][1]].size;
		for(int i=0;i<size;i++)Ans[now].Insert(Ans[Son[now][1]][i]);
		Merge(Ans[now],Data[Son[now][0]][1],Data[Son[now][1]][0]);
		Ans[now].Convex();
		Sum[now]=Sum[Son[now][0]]+Sum[Son[now][1]];
	}
	inline void Build(int &now,int left,int right)
	{
		now=++cnt;
		Left[now]=left;Right[now]=right;
		Data[now][0].Data=Allocate(right-left+3);
		Data[now][1].Data=Allocate(right-left+3);
		Ans[now].Data=Allocate(right-left+3);
		if(left==right)
		{
			Data[now][0].PushBack(Point(0,0));
			Data[now][0].PushBack(Point(1,Arr[left]));
			Data[now][1].PushBack(Point(0,0));
			Data[now][1].PushBack(Point(1,Arr[left]));
			Ans[now].PushBack(Point(0,0));
			Ans[now].PushBack(Point(1,Arr[left]));
			Sum[now]=Arr[left];
			return ; 
		}
		register int mid=(Left[now]+Right[now])>>1;
		Build(Son[now][0],left,mid);
		Build(Son[now][1],mid+1,right);
		MergeLeftRight(Data[now][0],Data[Son[now][0]][0],Data[Son[now][1]][0],Point(mid-Left[now]+1,Sum[Son[now][0]]));
		MergeLeftRight(Data[now][1],Data[Son[now][1]][1],Data[Son[now][0]][1],Point(Right[now]-mid,Sum[Son[now][1]]));
		PushUp(now);
	}
	inline Result Query(int now,int left,int right)
	{
		if(left<=Left[now]&&Right[now]<=right)
		{
			return Result(Data[now][0].MaxVal(),Data[now][1].MaxVal(),Ans[now].MaxVal(),Sum[now]+tag*(Right[now]-Left[now]+1));
		}
		register int mid=(Left[now]+Right[now])>>1;
		if(right<=mid)return Query(Son[now][0],left,right);
		else if(mid+1<=left)return Query(Son[now][1],left,right);
		else
		{
			Result tmp1=Query(Son[now][0],left,right);
			Result tmp2=Query(Son[now][1],left,right);
			return Merge(tmp1,tmp2);
		}
	}
}SegTree;
struct Operation
{
	int left,right,id;
	long long data;
	Operation(int left=0,int right=0,int id=0,long long data=0)
		:left(left),right(right),id(id),data(data){}
	inline friend bool operator<(const Operation& a,const Operation& b)
		{return a.data<b.data;} 
}Opt[600005];
int n,m,q,root;
long long ans[600005];
int main()
{
	freopen("tt.tou","r",stdin);
	freopen("tt.pot","w",stdout);
	scanf("%d%d",&n,&m);
	for(register int i=1;i<=n;i++)scanf("%lld",&Arr[i]);
	for(register int i=1;i<=m;i++)
	{
		register int opt;register long long data;scanf("%d",&opt);
		if(opt==1){scanf("%lld",&data);tag+=data;}
		else
		{
			int left,right;
			scanf("%d%d",&left,&right);
			if(left>right)std::swap(left,right);
			Opt[++q]=Operation(left,right,q,tag);
		}
	}
	std::sort(Opt+1,Opt+q+1);
	for(register int i=1;i<=n;i++)Arr[i]+=Opt[1].data;
	for(register int i=q;i>=1;i--)Opt[i].data-=Opt[1].data;
	SegTree.Build(root,1,n);
	for(register int i=1;i<=q;i++)
	{
		tag=Opt[i].data;
		ans[Opt[i].id]=SegTree.Query(root,Opt[i].left,Opt[i].right).ans;
	}
	for(register int i=1;i<=q;i++)printf("%lld\n",ans[i]);
	return 0;
}
2020/9/16 20:29
加载中...