[NOIP2022] 比赛

[NOIP2022] 比赛

很明显要离线,枚举右端点

对于\([L,R]\)中取子区间的最大值求和不是很好维护

定义\(f_l\)为当前左端点为\(l\),\(\sum\limits_{r=l}^RAns(l,r)\)

\(Query(l,r)\)就是\(\sum\limits_{i=l}^rf_i\),我们可以用线段树维护

定义\(ma_l\)为当前\(R\),\(A\)\((l,R)\)的最大值,\(mb_l\)同理

考虑我们加入一个\(R\)\(f,ma,mb\)的影响

很明显,\(ma,mb\)就是与\(A_R,B_R\)\(max\),又因为\(ma,mb\)单增为了方便我们找到第一个\(R\)大于的用区间覆盖维护

对于\(f\),其实就相当于对于\([1,R]\)所有的\(f_l+=(ma_l\times mb_l)\)

\(ma_l=x,mb_l=y\)

如果我们把线段树节点上的\(f\)拆分为\(c_{xy}\sum xy+c_x\sum x+c_y\sum y+c\sum1\),则上面的操作到线段树上就是\(c_{xy}+=1\)

而如果是区间覆盖实际上是可以做这样的拆分的:

\[Case1:A,B都没被覆盖 \\ 没影响 \\ Case2:A覆盖,B没 \\ 则xy,x要变,其中的c_{xy}\sum{xy}=c_{xy}x'\sum y,相当于这一项的系数到y上 \\ c_x到常数项 \\ Case3:B覆盖,A没 \\ 同理 \\ Case4:A,B都被覆盖 \\ 都到常数项 \]

由此,覆盖操作经拆分依旧可以互相转化

最后就是打标记的问题了,因为上面的我们要系数的增量,如果当前儿子有覆盖标记的话,下传的增量标记是要转化的

这里我们规定先传增量再传覆盖,这样保证所有增量在覆盖前面,维护的\(\sum xy\)对应的增量也是未覆盖的

#include<bits/stdc++.h>
#define int unsigned long long
#define ls 2*p
#define rs 2*p+1
using namespace std;
int T,n;
const int MAXN=2.5e5+5;
int a[MAXN];
int b[MAXN];
int q;
unsigned long long Ans[MAXN];
vector<pair<int,int> >query[MAXN];
int l,r;
struct Tag{
	unsigned long long addx,addy,addxy,addc;
	int clox,cloy;
};
struct Seg{
	unsigned long long datex,datey,datexy,date;
	int l,r;
	Tag lazy;
}Tree[MAXN*4];
void Build(int p,int l,int r)
{
	Tree[p].l=l;
	Tree[p].r=r;
	if(l==r)
	{
		return;
	}
	int mid=(l+r)>>1;
	Build(ls,l,mid);
	Build(rs,mid+1,r);
}
void Put(Seg &u,int Len,Tag t)
{
	if(u.lazy.clox&&u.lazy.cloy)
	{
		u.lazy.addc+=t.addxy*u.lazy.clox*u.lazy.cloy+t.addx*u.lazy.clox+t.addy*u.lazy.cloy+t.addc;
	}
	else if(u.lazy.clox)
	{
		u.lazy.addy+=t.addxy*u.lazy.clox+t.addy;
		u.lazy.addc+=t.addx*u.lazy.clox+t.addc;
	}
	else if(u.lazy.cloy)
	{
		u.lazy.addx+=t.addxy*u.lazy.cloy+t.addx;
		u.lazy.addc+=t.addy*u.lazy.cloy+t.addc;
	}
	else
	{
		u.lazy.addxy+=t.addxy;
		u.lazy.addx+=t.addx;
		u.lazy.addy+=t.addy;
		u.lazy.addc+=t.addc;
	}
	if(t.clox)
	{
		u.lazy.clox=t.clox;
	}
	if(t.cloy)
	{
		u.lazy.cloy=t.cloy;
	}
	
	u.date+=u.datex*t.addx+u.datey*t.addy+u.datexy*t.addxy+Len*t.addc;
	if(t.clox&&t.cloy)
	{
		u.datex=t.clox*Len;
		u.datey=t.cloy*Len;
		u.datexy=t.clox*t.cloy*Len;
	}
	else if(t.clox)
	{
		u.datex=t.clox*Len;
		u.datexy=u.datey*t.clox;
	}
	else if(t.cloy)
	{
		u.datey=t.cloy*Len;
		u.datexy=u.datex*t.cloy;
	}
}
void push_up(int p)
{
	Tree[p].date=Tree[ls].date+Tree[rs].date;
	Tree[p].datex=Tree[ls].datex+Tree[rs].datex;
	Tree[p].datey=Tree[ls].datey+Tree[rs].datey;
	Tree[p].datexy=Tree[ls].datexy+Tree[rs].datexy;
}
void Clear(Tag &x)
{
	x.addc=0;
	x.addx=0;
	x.addy=0;
	x.addxy=0;
	x.clox=0;
	x.cloy=0;
	return;
}
Tag Make(int clox,int cloy,unsigned long long addx,unsigned long long addy,unsigned long long addc,unsigned long long addxy)
{
	Tag nyh520;
	nyh520.clox=clox;
	nyh520.cloy=cloy;
	nyh520.addx=addx;
	nyh520.addy=addy;
	nyh520.addc=addc;
	nyh520.addxy=addxy;
	return nyh520;
}
void push_down(int p)
{
	Put(Tree[ls],Tree[ls].r-Tree[ls].l+1,Tree[p].lazy);
	Put(Tree[rs],Tree[rs].r-Tree[rs].l+1,Tree[p].lazy);
	Clear(Tree[p].lazy);
//	if((Tree[p].lazy.clox||Tree[p].lazy.cloy))
//	{
//		printf("why\n");
//	}
}
void Update(int p,int l,int r,Tag x)
{
	if(Tree[p].l>=l&&Tree[p].r<=r)
	{
		Put(Tree[p],Tree[p].r-Tree[p].l+1,x);
		return;
	}
	push_down(p);
	int mid=(Tree[p].l+Tree[p].r)>>1;
	if(l<=mid)
	{
		Update(ls,l,r,x);
	}
	if(r>mid)
	{
		Update(rs,l,r,x);
	}
	push_up(p);
}
int twice;
unsigned long long Query(int p,int l,int r)
{
	if(Tree[p].l>=l&&Tree[p].r<=r)
	{
		return Tree[p].date;
	}
//	if(twice&&(Tree[p].lazy.clox||Tree[p].lazy.cloy))
//	{
//		printf("wdg\n");
//	}
	push_down(p);
//	if((Tree[p].lazy.clox||Tree[p].lazy.cloy))
//	{
//		printf("why\n");
//	}
	int mid=(Tree[p].l+Tree[p].r)>>1;
	unsigned long long Res=0;
	if(l<=mid)
	{
		Res+=Query(ls,l,r);
	 } 
	if(r>mid)
	{
		Res+=Query(rs,l,r);
	}
	push_up(p);
	return Res;
}
int dp1[MAXN][25];
int dp2[MAXN][25];
int Query1(int x,int y)
{
    int k=log2(y-x+1);
    return max(dp1[x][k],dp1[y-(1<<k)+1][k]);
}
int Query2(int x,int y)
{
    int k=log2(y-x+1);
    return max(dp2[x][k],dp2[y-(1<<k)+1][k]);
}
signed main()
{
	scanf("%llu %llu",&T,&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%llu",&a[i]);	
	}	
	for(int i=1;i<=n;i++)
	{
		scanf("%llu",&b[i]);
	}
	for(int i=1;i<=n;i++)
	{
		dp1[i][0]=a[i];
	}
	for(int j=1;(1<<j)<=n;j++)
	{
		for(int i=1;i+(1<<j)-1<=n;i++)
		{
			dp1[i][j]=max(dp1[i][j-1],dp1[i+(1<<j-1)][j-1]);
		}
	}
	for(int i=1;i<=n;i++)
	{
		dp2[i][0]=b[i];
	}
	for(int j=1;(1<<j)<=n;j++)
	{
		for(int i=1;i+(1<<j)-1<=n;i++)
		{
			dp2[i][j]=max(dp2[i][j-1],dp2[i+(1<<j-1)][j-1]);
		}
	}
	scanf("%llu",&q);
	for(int i=1;i<=q;i++)
	{
		scanf("%llu %llu",&l,&r);
		query[r].push_back(make_pair(l,i));
	}
	Build(1,1,n);
	for(int i=1;i<=n;i++)
	{
		l=1;
		r=i;
		int key=i;
		while(l<=r)
		{
			int mid=(l+r)>>1;
			if(Query1(mid,i)==a[i])
			{
				key=mid;
				r=mid-1;
			}
			else
			{
				l=mid+1;
			}
		}
		Update(1,key,i,Make(a[i],0,0,0,0,0));
	//	printf("%d ",key);
		l=1;
		r=i;
		key=i;
		while(l<=r)
		{
			int mid=(l+r)>>1;
			if(Query2(mid,i)==b[i])
			{
				key=mid;
				r=mid-1;
			}
			else
			{
				l=mid+1;
			}
		}
		Update(1,key,i,Make(0,b[i],0,0,0,0));
		Update(1,1,i,Make(0,0,0,0,0,1));
		//printf("%d\n",key);
		for(int j=0;j<query[i].size();j++)
		{
			pair<int,int>efc=query[i][j];
			Ans[efc.second]=Query(1,efc.first,i);
			twice=1;
			if(Query(1,efc.first,i)!=Query(1,efc.first,i))
			{
				printf(">fgg\n");
			}
			twice=0;
		}
	}
	for(int i=1;i<=q;i++)
	{
		printf("%llu\n",Ans[i]);
	}
} 
posted @ 2022-12-12 21:50  kid_magic  阅读(154)  评论(1编辑  收藏  举报