zoukankan      html  css  js  c++  java
  • 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
    ",tmp);
    //			printf("%lld %lld
    ",tmp1.cost,tmp2.cost);
    			printf("%lld
    ",(tmp1.cost+tmp2.cost)%MOD);
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    怎样解决Script error报错问题
    怎样监听页面加载完成事件
    怎样推迟某个函数的执行
    怎样获取网页加载到现在的时间
    怎样获取用户当前选中的文本
    怎样调出打印界面
    怎样取余或取整
    怎样让元素节点滚动到特定位置
    怎样将页面滚动至特定位置
    怎样移动浏览器窗口位置
  • 原文地址:https://www.cnblogs.com/Point-King/p/13999051.html
Copyright © 2011-2022 走看看