zoukankan      html  css  js  c++  java
  • P7405-[JOI 2021 Final]雪玉【二分】

    正题

    题目链接:https://www.luogu.com.cn/problem/P7405


    题目大意

    (n)个点在坐标轴上,(q)次每次所有点向一个方向移动若干步,每个点的权值是它第一次覆盖的区间长度(也就是一个区间只能贡献到第一次经过它的点)。

    求所有点的最终权值。

    (1leq n,qleq 2 imes 10^5)


    解题思路

    因为两个点的区间只会被这两个点覆盖,所以考虑求出每个区间被两边各占了多少。

    先去掉无用的条件,求出一个数组(f)满足正负交替表示一左一右,正负的绝对值各自递增。

    然后在(f)数组上二分出两个点覆盖的区间第一次相交的时候就可以计算各自被覆盖多少了。

    时间复杂度(O(nlog n))


    code

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define ll long long
    using namespace std;
    const ll N=2e5+10;
    ll n,m,Q,lmax,rmax,x[N],g[N],f[N],w[N];
    signed main()
    {
    	scanf("%lld%lld",&n,&Q);
    	for(ll i=1;i<=n;i++)scanf("%lld",&x[i]);
    	for(ll i=1;i<=Q;i++){
    		scanf("%lld",&g[i]);g[i]+=g[i-1];
    		if(g[i]>rmax){
    			if(f[m]<=0)rmax=f[++m]=g[i];
    			else rmax=f[m]=g[i];
    		}
    		if(g[i]<lmax){
    			if(f[m]>=0)lmax=f[++m]=g[i];
    			else lmax=f[m]=g[i];
    		}
    	}
    	w[1]-=lmax;w[n]+=rmax;
    	for(ll i=1;i<n;i++){
    		ll len=x[i+1]-x[i];
    		ll l=0,r=m-2;
    		while(l<=r){
    			ll mid=(l+r)>>1;
    			if(abs(f[mid])+abs(f[mid+1])>=len)r=mid-1;
    			else l=mid+1;
    		}
    		if(abs(f[l])+abs(f[l+1])>=len){
    			if(f[l+1]>0)w[i+1]-=f[l],w[i]+=len+f[l];
    			else w[i]+=f[l],w[i+1]+=len-f[l];
    		}
    		else{
    			if(f[l+1]>0)w[i+1]-=f[l],w[i]+=f[l+1];
    			else w[i]+=f[l],w[i+1]-=f[l+1];
    		}
    	}
    	for(ll i=1;i<=n;i++)
    		printf("%lld
    ",w[i]);
    	return 0;
    }
    
  • 相关阅读:
    Java输入输出流详解2
    Java输入输出流详解(转)
    java泛型
    E-R图学习笔记
    MongoDB工具
    MongoDB安装
    mongodb-参考其他
    mongodb学习笔记
    WebService学习笔记
    nutch笔记
  • 原文地址:https://www.cnblogs.com/QuantAsk/p/15026574.html
Copyright © 2011-2022 走看看