ARC047D

发布时间 2023-11-09 09:43:44作者: yinhee

首杀问号题,虽然没有问号题的难度,但是至少是自己想出来的。

对于操作一和二,我们直接用分一个数组记录下来,\(O(nq)\)

对于操作三,我们思考怎么样通过上面记录的信息处理答案。发现对于一个矩形,只要确定了 \(x+y\) 的值,\(x-y\) 的值就是一个区间,因为矩形的约束可以变成 \(2\times A\le(x+y)+(x-y)\le 2\times B,2\times C\le(x+y)-(x-y)\le 2\times D\)。这启示我们可以类似莫队,维护两个指针。

但是删除操作是比较难做的。我们先考虑不用删除的情况是什么,发现在矩形左上,右下角割出一个等腰直角三角形,这是可以直接做的,因为只会有加入。

然后考虑剩下的部分,发现这是一个平行四边形。放入刚才的思路中,这就变成了一个滑动窗口,直接单调队列维护即可。时间复杂度 \(O(nq)\)

细节还是不少的。首先要分成奇偶来讨论,其次单调队列部分要根据矩形形状决定加/删的是左端点还是右端点。处理答案可以像我一样,手写一个记录最大值和出现次数的 struct。

写得有点冗长,但是很多都是可以复制粘贴的,也不算很恶心,主要是样例强度足够。

code:

点击查看代码
int n,m,a[N],b[N];
struct node{
	int x,y;
	node(int _x=-inf,int _y=0){x=_x,y=_y;}
	node operator+(const node &tmp)const{
		node r=node(x,y);
		if(tmp.x>r.x)r.x=tmp.x,r.y=tmp.y;
		else if(tmp.x==r.x)r.y+=tmp.y;
		return r;
	}
};
struct Node{node x;int y;};
void Yorushika(){
	scanf("%d%d",&n,&m);
	if(n&1)n++;
	rep(i,1,m){
		int op,x,y,k;
		scanf("%d%d%d",&op,&x,&y);
		if(op==1){
			scanf("%d",&k);
			rep(j,x,y)a[j]+=k;
		}else if(op==2){
			scanf("%d",&k);
			rep(j,x,y)b[j+n]+=k;
		}else{
			int X,Y;scanf("%d%d",&X,&Y);
			x*=2,y*=2,X*=2,Y*=2;
			int l[2]={-1,-1},r[2]={0,0},pl=n*2,pr=0;
			node mx[2],ans;
			rep(i,0,n*2){
				int la=x-i,ra=y-i,lb=i-Y,rb=i-X,p=i&1;
				int L=max(la,lb)+n,R=min(ra,rb)+n;
				if(L>R)continue;
				if(l[p]<0)for(int j=l[p]=L;j<=(r[p]=R);j+=2)mx[p]=mx[p]+node(b[j],1);
				if(L>l[p]||R<r[p])break;
				while(r[p]<R)r[p]+=2,mx[p]=mx[p]+node(b[r[p]],1);
				while(l[p]>L)l[p]-=2,mx[p]=mx[p]+node(b[l[p]],1);
				node tmp=mx[p];tmp.x+=a[i];
				ans=ans+tmp,pl=i;
			}
			l[0]=l[1]=-1,r[0]=r[1]=0,mx[0]=mx[1]=node();
			drep(i,n*2,pl+1){
				int la=x-i,ra=y-i,lb=i-Y,rb=i-X,p=i&1;
				int L=max(la,lb)+n,R=min(ra,rb)+n;
				if(L>R)continue;
				if(l[p]<0)for(int j=l[p]=L;j<=(r[p]=R);j+=2)mx[p]=mx[p]+node(b[j],1);
				if(L>l[p]||R<r[p])break;
				while(r[p]<R)r[p]+=2,mx[p]=mx[p]+node(b[r[p]],1);
				while(l[p]>L)l[p]-=2,mx[p]=mx[p]+node(b[l[p]],1);
				node tmp=mx[i&1];tmp.x+=a[i];
				ans=ans+tmp,pr=i;
			}
			l[0]=l[1]=-1,r[0]=r[1]=0,mx[0]=mx[1]=node();
			deque<node> q[2];
			if(X-Y<=x-y){
				rep(i,pl+1,pr-1){
					int la=x-i,ra=y-i,lb=i-Y,rb=i-X,p=i&1;
					int L=max(la,lb)+n,R=min(ra,rb)+n;
					if(L>R)continue;
					if(l[p]<0)for(int j=r[p]=R;j>=(l[p]=L);j-=2){
						while(q[p].size()&&q[p].back().x<b[j])q[p].pop_back();
						if(q[p].size()&&q[p].back().x==b[j]){
							node tmp=q[p].back();
							q[p].pop_back();
							tmp.y++;
							q[p].push_back(tmp);
						}else q[p].push_back(node(b[j],1));
					}else{
						if(q[p].front().x==b[r[p]]){
							node tmp=q[p].front();
							q[p].pop_front();
							tmp.y--;
							if(tmp.y)q[p].push_front(tmp);
						}
						l[p]-=2,r[p]-=2;
						while(q[p].size()&&q[p].back().x<b[l[p]])q[p].pop_back();
						if(q[p].size()&&q[p].back().x==b[l[p]]){
							node tmp=q[p].back();
							q[p].pop_back();
							tmp.y++;
							q[p].push_back(tmp);
						}else q[p].push_back(node(b[l[p]],1));
					}
					node tmp=q[p].front();tmp.x+=a[i];
					ans=ans+tmp;
				}
			}else{
				rep(i,pl+1,pr-1){
					int la=x-i,ra=y-i,lb=i-Y,rb=i-X,p=i&1;
					int L=max(la,lb)+n,R=min(ra,rb)+n;
					if(L>R)continue;
					if(l[p]<0)for(int j=l[p]=L;j<=(r[p]=R);j+=2){
						while(q[p].size()&&q[p].back().x<b[j])q[p].pop_back();
						if(q[p].size()&&q[p].back().x==b[j]){
							node tmp=q[p].back();
							q[p].pop_back();
							tmp.y++;
							q[p].push_back(tmp);
						}else q[p].push_back(node(b[j],1));
					}else{
						if(q[p].front().x==b[l[p]]){
							node tmp=q[p].front();
							q[p].pop_front();
							tmp.y--;
							if(tmp.y)q[p].push_front(tmp);
						}
						l[p]+=2,r[p]+=2;
						while(q[p].size()&&q[p].back().x<b[r[p]])q[p].pop_back();
						if(q[p].size()&&q[p].back().x==b[r[p]]){
							node tmp=q[p].back();
							q[p].pop_back();
							tmp.y++;
							q[p].push_back(tmp);
						}else q[p].push_back(node(b[r[p]],1));
					}
					node tmp=q[p].front();tmp.x+=a[i];
					ans=ans+tmp;
				}
			}
			printf("%d %d\n",ans.x,ans.y);
		}
	}
}
signed main(){
	int t=1;
	//	scanf("%d",&t);
	while(t--)
		Yorushika();
}