【jzoj5232】【NOIP2017模拟A组模拟8.5】【带权排序】【线段树】

题目大意

这里写图片描述

解题思路

考虑维护f[i]表示填i时当前数期望前面有多少个数比自己小,发现添加一个数对f增加一个等差数列和一段定值,计算贡献时区间求和,可以用线段树维护。

code

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define LF double
#define LL long long
#define ULL unsigned int
#define fo(i,j,k) for(int i=j;i<=k;i++)
#define fd(i,j,k) for(int i=j;i>=k;i--)
#define fr(i,j) for(int i=begin[j];i;i=next[i])
using namespace std;
int const mn=1e5,ma=1e9,mo=1e9+7;
int n,ans,pon,sum[mn*80+9],tag[mn*80+9],ta2[mn*80+9],son[mn*80+9][2],
    s[mn+9],l[mn+9],r[mn+9];
int pow(int x,int y){
    int z=1;
    while(y){
        if(y&1)z=1ll*z*x%mo;
        x=1ll*x*x%mo;
        y/=2;
    }
    return z;
}
int calc(int x,int y,int z){
    return (1ll*x*z+1ll*(z-1)*z/2%mo*y)%mo;
}
void uptag(int p,int l,int r){
    if((tag[p]||ta2[p])&&(l!=r)){
        int md=(l+r)/2,x=tag[p],y=ta2[p];
        if(!son[p][0])son[p][0]=++pon;
        if(!son[p][1])son[p][1]=++pon;
        int ls=son[p][0],rs=son[p][1];
        tag[ls]=(tag[ls]+x)%mo;
        ta2[ls]=(ta2[ls]+y)%mo;
        sum[ls]=(sum[ls]+calc(x,y,md-l+1))%mo;
        tag[rs]=(tag[rs]+x+1ll*y*(md-l+1))%mo;
        ta2[rs]=(ta2[rs]+y)%mo;
        sum[rs]=(sum[rs]+calc((x+1ll*y*(md-l+1))%mo,y,r-md))%mo;
        tag[p]=ta2[p]=0;
    }
}
void oper(int p,int l,int r,int u,int v,int x,int y){
    uptag(p,l,r);
    int md=(l+r)/2;
    if((l==u)&&(r==v)){
        sum[p]=(sum[p]+calc(x,y,r-l+1))%mo;
        tag[p]=(tag[p]+x)%mo;
        ta2[p]=(ta2[p]+y)%mo;
        return;
    }
    if(v<=md){
        if(!son[p][0])son[p][0]=++pon;
        oper(son[p][0],l,md,u,v,x,y);
    }else if(md<u){
        if(!son[p][1])son[p][1]=++pon;
        oper(son[p][1],md+1,r,u,v,x,y);
    }else{
        if(!son[p][0])son[p][0]=++pon;
        if(!son[p][1])son[p][1]=++pon;
        oper(son[p][0],l,md,u,md,x,y),
        oper(son[p][1],md+1,r,md+1,v,(x+1ll*y*(md+1-u))%mo,y);
    }
    sum[p]=(sum[son[p][0]]+sum[son[p][1]])%mo;
}
int qury(int p,int l,int r,int u,int v){
    uptag(p,l,r);
    int md=(l+r)/2;
    if((l==u)&&(r==v))return sum[p];
    if(v<=md)return qury(son[p][0],l,md,u,v);
    else if(md<u)return qury(son[p][1],md+1,r,u,v);
    else return (qury(son[p][0],l,md,u,md)+qury(son[p][1],md+1,r,md+1,v))%mo;
}
int main(){
    freopen("sort.in","r",stdin);
    freopen("sort.out","w",stdout);
    scanf("%d",&n);
    fo(i,1,n)scanf("%d%d%d",&s[i],&l[i],&r[i]),ans=(ans+s[i])%mo;
    pon=1;
    fo(i,1,n){
        LL tmp=pow(r[i]-l[i]+1,mo-2),tm2=tmp*s[i]%mo;
        ans=(ans+qury(1,0,ma,l[i],r[i])*tm2)%mo;
        oper(1,0,ma,l[i],r[i],tmp,tmp);
        if(r[i]+1<=ma)oper(1,0,ma,r[i]+1,ma,1,0);
    }
    fo(i,0,pon)sum[i]=tag[i]=ta2[i]=son[i][0]=son[i][1]=0;
    pon=1;
    fd(i,n,1){
        LL tmp=pow(r[i]-l[i]+1,mo-2),tm2=tmp*s[i]%mo;
        if(r[i]-1>=0)ans=(ans+qury(1,0,ma,max(l[i]-1,0),r[i]-1)*tm2)%mo;
        oper(1,0,ma,l[i],r[i],tmp,tmp);
        if(r[i]+1<=ma)oper(1,0,ma,r[i]+1,ma,1,0);
    }
    printf("%d",(ans+mo)%mo);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值