【jzoj4882】【多段线性函数】

题目大意

【jzoj4882】【多段线性函数】_第1张图片

解题思路

考虑一个数在区间左边和右边才贡献,先把标记打在边界,然后像前缀和那样传递,然后离散化选的点一定在边界上,枚举选的点利用预处理的信息即可求出答案。

code

#include
#include
#include
#include
#include
#include
#define LL long long
#define LD double
#define max(a,b) ((a>b)?a:b)
#define min(a,b) ((a>b)?b:a)
#define fo(i,j,k) for(int i=j;i<=k;i++)
#define fd(i,j,k) for(int i=j;i>=k;i--)
using namespace std;
int const inf=1e9,maxn=1e5,mod1=1e9+7,mod2=998244353,size=29989;
int n,l[maxn+10],r[maxn+10],a[maxn*2+10],b[maxn*2+10],c[maxn*2+10],
lnum[maxn*2+10],rnum[maxn*2+10];
LL lsum[maxn*2+10],rsum[maxn*2+10];
int get(int x){
    int l=1,r=a[0];
    for(;l!=r;){
        int m=(l+r)/2;
        if(a[m]<x)l=m+1;
        else r=m;
    }
    return b[l];
}
int main(){
    freopen("linear.in","r",stdin);
    freopen("linear.out","w",stdout);
    scanf("%d",&n);
    fo(i,1,n){
        scanf("%d%d",&l[i],&r[i]);
        a[++a[0]]=l[i];a[++a[0]]=r[i];
    }
    sort(a+1,a+a[0]+1);
    b[1]=1;c[1]=a[1];fo(i,2,a[0]){b[i]=b[i-1]+(a[i]!=a[i-1]),c[b[i]]=a[i];}
    fo(i,1,n){
        l[i]=get(l[i]);rnum[l[i]]++;rsum[l[i]]+=c[l[i]];
        r[i]=get(r[i]);lnum[r[i]]++;lsum[r[i]]+=c[r[i]];
    }
    fd(i,b[a[0]],1){
        rnum[i]+=rnum[i+1];
        rsum[i]+=rsum[i+1];
    }
    LL mi=1e16;int beg,end;
    fo(i,1,b[a[0]]){
        lnum[i]+=lnum[i-1];
        lsum[i]+=lsum[i-1];
        if(1ll*c[i]*lnum[i]-lsum[i]+rsum[i]-1ll*c[i]*rnum[i]1ll*c[i]*lnum[i]-lsum[i]+rsum[i]-1ll*c[i]*rnum[i];
            beg=end=c[i];
        }else if(1ll*c[i]*lnum[i]-lsum[i]+rsum[i]-1ll*c[i]*rnum[i]==mi)end=c[i];
    }
    printf("%d %d",beg,end);
    return 0;
}

你可能感兴趣的:(jzoj,其他各种乱搞)