[LOJ]#6515. 「雅礼集训 2018 Day10」贪玩蓝月

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/baidu_36797646/article/details/88163176

Solution

离线做法很简单,就是线段树分治,不过复杂度是 q m o d log qmod\log
考虑在线做法,在线段树分治中,我们并没有利用到删除以及加入都只会在两端进行这个性质,我们考虑用两个栈分别维护两端,每次加入一个数就暴力做背包,删除就删除栈顶。当某一个栈被删空了之后,就把现有的数均等分成两份,扔进两个栈中暴力重构。
询问的话,一开始也想过分成两段维护,但一直没有办法快速合并两段的状态,其实并不需要合并起来,枚举第一个栈中贡献的余数,那么就相当于询问另一栈中的区间最大值,可以发现每次询问的区间都是长度相等的一段,所以可以用单调队列维护最大值。
复杂度是 q m o d qmod

Code

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define pa pair<int,int>
const int Maxn=50010;
const LL inf=4485090715960753727LL;
int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
	return x*f;
}
int m,mod,w[Maxn<<1],v[Maxn<<1];
LL s1[Maxn][505],s2[Maxn][505];
int t1=0,t2=0,l=50001,r=50000,mid=50000;
char op[5];
void clear1(int x){memset(s1[x],-63,sizeof(s1[x]));}
void clear2(int x){memset(s2[x],-63,sizeof(s2[x]));}
void add1(int x)
{
	t1++;clear1(t1);
	memcpy(s1[t1],s1[t1-1],sizeof(s1[t1]));
	for(int i=0;i<mod;i++)
	{
		int j=(i+w[x])%mod;
		s1[t1][j]=max(s1[t1][j],s1[t1-1][i]+v[x]);
	}
}
void add2(int x)
{
	t2++;clear2(t2);
	memcpy(s2[t2],s2[t2-1],sizeof(s2[t2]));
	for(int i=0;i<mod;i++)
	{
		int j=(i+w[x])%mod;
		s2[t2][j]=max(s2[t2][j],s2[t2-1][i]+v[x]);
	}
}
vector<int>h[1005];
int tot,to[505];LL Ans[505],a[1005];
int q[505];
LL query(int L,int R)
{
	LL re=-inf;tot=0;int len=R-L+1;
	for(int i=0;i<mod+mod;i++)h[i].clear();
	for(int i=0;i<mod;i++)
	{
		int ll=L-i,rr=R-i;
		if(ll<0)ll+=mod;if(rr<0)rr+=mod;
		if(ll>rr)rr+=mod;
		h[rr].push_back(to[i]=++tot);
	}
	int head=1,tail=0;
	for(int i=0;i<mod+mod;i++)
	{
		LL x=s2[t2][i%mod];a[i]=x;
		while(head<=tail&&i-q[head]+1>len)head++;
		while(head<=tail&&x>=a[q[tail]])tail--;
		q[++tail]=i;
		for(int j=0;j<h[i].size();j++)Ans[h[i][j]]=a[q[head]];
	}
	for(int i=0;i<mod;i++)
	if(s1[t1][i]>=0&&Ans[to[i]]>=0)re=max(re,s1[t1][i]+Ans[to[i]]);
	if(re<=-inf)return -1;
	return re;
}
void rebuild()
{
	mid=l+r>>1;
	t1=t2=0;clear1(0);clear2(0);s1[0][0]=s2[0][0]=0;
	for(int i=mid;i>=l;i--)add1(i);
	for(int i=mid+1;i<=r;i++)add2(i);
}
int main()
{
	read();
	m=read(),mod=read();
	clear1(0),clear2(0);
	s1[0][0]=s2[0][0]=0;
	while(m--)
	{
		scanf("%s",op);
		if(op[0]=='I')
		{
			if(op[1]=='F')l--,w[l]=read()%mod,v[l]=read(),add1(l);
			else r++,w[r]=read()%mod,v[r]=read(),add2(r);
		}
		else if(op[0]=='Q')
		{
			int L=read(),R=read();
			printf("%lld\n",query(L,R));
		}
		else
		{
			if(op[1]=='F')
			{
				l++,t1--;
				if(l>mid)rebuild();
			}
			else
			{
				r--,t2--;
				if(r<=mid)rebuild();
			}
		}
	}
}

猜你喜欢

转载自blog.csdn.net/baidu_36797646/article/details/88163176
今日推荐