CF1030F Putting Boxes Together

这道题唯一重要的是告诉了我一条直线上带权选址问题的通解。

题解

先将所有点根据距离排序,选址点 \(x\) 即是距离最左边的距离最小的点且满足:

\[\sum_{i=l}^x w_i \ge \sum_{i=x+1}^r w_i \]

然后用树状数组和线段树维护一下就可以了。

代码如下

#include<bits/stdc++.h>
using namespace std;
#define Lint long long
const int N=2e5+5;
const Lint MOD=1e9+7;
int n,m;
struct Box{Lint loc,weight;}a[N];
struct Push_R{Lint l,r,weight,cost;};
Push_R operator + (const Push_R a,const Push_R b)
{
	Push_R res;
	res.weight=(a.weight+b.weight)%MOD;
	res.l=b.l-(a.r-a.l+1),res.r=b.r;
	res.cost=(a.cost+b.cost+a.weight*(b.l-a.r-1))%MOD;
	return res;
}
struct Push_L{Lint l,r,weight,cost;};
Push_L operator + (const Push_L a,const Push_L b)
{
	Push_L res;
	res.weight=(a.weight+b.weight)%MOD;
	res.l=a.l,res.r=a.r+(b.r-b.l+1);
	res.cost=(a.cost+b.cost+b.weight*(b.l-a.r-1))%MOD;
	return res;
}
struct Seg_Tree
{
	struct Node{Push_L L;Push_R R;}tr[N<<2];
	void up(int u)
	{
		tr[u].L=tr[u<<1].L+tr[u<<1|1].L;
		tr[u].R=tr[u<<1].R+tr[u<<1|1].R;
	}
	void build(int u,int l,int r,Box a[])
	{
		if(l==r)
		{
			tr[u].L.l=tr[u].L.r=a[l].loc;
			tr[u].L.weight=a[l].weight,tr[u].L.cost=0;
			tr[u].R.l=tr[u].R.r=a[l].loc;
			tr[u].R.weight=a[l].weight,tr[u].R.cost=0;
			return ;
		}
		int mid=(l+r)>>1;
		build(u<<1,l,mid,a);
		build(u<<1|1,mid+1,r,a);
		up(u);
	}
	void chg(int u,int l,int r,int x,Box z)
	{
		if(l==r)
		{
			tr[u].L.weight=z.weight;
			tr[u].R.weight=z.weight;
			return ;
		}
		int mid=(l+r)>>1;
		if(x<=mid) chg(u<<1,l,mid,x,z);
		else chg(u<<1|1,mid+1,r,x,z);
		up(u);
	}
	Push_L query_L(int u,int l,int r,int x,int y)
	{
		if(x<=l&&r<=y) return tr[u].L;
		int mid=(l+r)>>1;Push_L tmp1,tmp2;
		if(x<=mid) tmp1=query_L(u<<1,l,mid,x,y);
		if(y>mid) tmp2=query_L(u<<1|1,mid+1,r,x,y);
		if(x<=mid&&y>mid) return tmp1+tmp2;
		return x<=mid?tmp1:tmp2;
	}
	Push_R query_R(int u,int l,int r,int x,int y)
	{
		if(x<=l&&r<=y) return tr[u].R;
		int mid=(l+r)>>1;Push_R tmp1,tmp2;
		if(x<=mid) tmp1=query_R(u<<1,l,mid,x,y);
		if(y>mid) tmp2=query_R(u<<1|1,mid+1,r,x,y);
		if(x<=mid&&y>mid) return tmp1+tmp2;
		return x<=mid?tmp1:tmp2;
	}
}t1;
struct Tree_Array
{
	Lint tr[N];
	int lowbit(int x){return x&(-x);}
	void add(int k,Lint x){for(;k<=n;k+=lowbit(k))tr[k]+=x;}
	Lint sum(int k){Lint res=0;for(;k;k-=lowbit(k))res+=tr[k];return res;}
}t2;
int main()
{
	cin>>n>>m;
	for(int i=1;i<=n;++i) scanf("%lld",&a[i].loc);
	for(int i=1;i<=n;++i) scanf("%lld",&a[i].weight);
	for(int i=1;i<=n;++i) t2.add(i,a[i].weight);
	t1.build(1,1,n,a);
	while(m--)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		if(x<0)
		{
			t2.add(-x,-a[-x].weight);
			a[-x].weight=y;
			t1.chg(1,1,n,-x,a[-x]);
			t2.add(-x,a[-x].weight);
		}
		else
		{
			int l=x,r=y,tmp=-1;
			while(l<=r)
			{
				int mid=(l+r)>>1;
				Lint sum1=t2.sum(mid)-t2.sum(x-1);
				Lint sum2=t2.sum(y)-t2.sum(mid);
				if(sum1>=sum2)
				r=mid-1,tmp=mid;
				else l=mid+1;
			}
			Push_R tmp1=t1.query_R(1,1,n,x,tmp);
			Push_L tmp2=t1.query_L(1,1,n,tmp,y);
//			printf("%d\n",tmp);
//			printf("%lld %lld\n",tmp1.cost,tmp2.cost);
			printf("%lld\n",(tmp1.cost+tmp2.cost)%MOD);
		}
	}
	return 0;
}
posted @ 2020-11-18 12:02  Point_King  阅读(60)  评论(0编辑  收藏  举报