JZOJ5232 带权排序

Description

WWT刚学会了归并排序。他在书上了解到,归并排序是一个稳定的排序算 法,也就是说,假如在原序列中,$a_i=a_j$且$i<j$,令$p_i$表示排序后$i$的位置,那 么满足$p_i<p_j$。 WWT自作主张地给每个位置$i$设定了权值$s_i$。对于一个长度为$n$的序列$A$, WWT先用归并排序给$A$排序,并得到$p_i$。令$f(A)$=$\sum_{i=1}^n s_ip_i$,WWT称$f(A)$为$A$的魅 力值。 WWT已经学会了怎么在给定$A$的情况下,求出$f(A)$。他在思考一个更为深 奥的哲学问题。假如$A$的每个元素$A_i$是随机的,那么$E[f(A)]$会是多少呢? 具体而言,$A_i$的取值是$[l_i,r_i]这个闭区间中的随机整数,即$A_i$会等概率地 等于区间中的任一整数。WWT想求出在这个条件下,$f(A)$的期望会是多少?

Solution

$$E(f(A))=E\left( \sum_{i=1}^n s_i p_i \right)=\sum_{i=1}^n s_iE(p_i)$$

令$f_i$为所有比$i$小的数的个数,则有

$$E(f(A))=\sum_{i=1}^n s_i f_i + \sum_{i=1}^n s_i$$

$$E(f_i)=\sum_{j< i} P(a_j \leq a_i) + \sum_{j> i} P(a_j < a_i)$$

讨论$\sum_{j< i} P(a_j \leq a_i)$的求解

当$l_j \leq a_i= x \leq r_j$时,$a_j$在$[l_j,x]$取值有贡献,所以$P(a_j \leq a_i)=\frac{x-l_j+1}{r_j-l_j+1}$

当$r_j < x$时,$a_j$总有贡献,所以$P(a_j \leq a_i)=1$

那么发现贡献总是能写成等差数列的形式,使用动态开点线段树维护,以取值为下标,维护区间求和和区间修改的操作

注意在线段树上区间加等差数列的操作

#pragma GCC optimize(2)
#include<iostream>
#include<cstdio>
using namespace std;
long long n,s[100005],l[100005],r[100005],ans,tot,root;
const long long mod=1000000007;
struct Tree
{
    long long ls,rs,A1,d,sum;
}tree[10000005];
inline long long read()
{
    long long f=1,w=0;
    char ch=0;
    while(ch<'0'||ch>'9')
    {
        if(ch=='-')
        {
            f=-1;
        }
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        w=(w<<1)+(w<<3)+ch-'0';
        ch=getchar();
    }
    return f*w;
}
long long ksm(long long a,long long p)
{
    long long ret=1ll;
    while(p)
    {
        if(p&1)
        {
            (ret*=a)%=mod;
        }
        (a*=a)%=mod;
        p>>=1;
    }
    return ret;
}
void pushdown(long long i,long long l,long long r)
{
    if(tree[i].A1||tree[i].d)
    {
        if(l!=r)
        {
            if(!tree[i].ls)
            {
                tree[i].ls=++tot;
            }
            if(!tree[i].rs)
            {
                tree[i].rs=++tot;
            }
            long long mid=l+r>>1;
            (tree[tree[i].ls].A1+=tree[i].A1)%=mod;
            (tree[tree[i].rs].A1+=(mid+1-l)*tree[i].d+tree[i].A1)%=mod;
            (tree[tree[i].ls].d+=tree[i].d)%=mod;
            (tree[tree[i].rs].d+=tree[i].d)%=mod;
        }
        (tree[i].sum+=(tree[i].A1+tree[i].A1+tree[i].d*(r-l)%mod)*(r-l+1)%mod*500000004ll%mod)%=mod;
        tree[i].A1=tree[i].d=0;
    }
}
long long query(long long &i,long long l,long long r,long long L,long long R)
{
    if(!i)
    {
        return 0;
    }
    pushdown(i,l,r);
    if(L<=l&&r<=R)
    {
        return tree[i].sum;
    }
    long long mid=l+r>>1,ret=0;
    if(L<=mid)
    {
        (ret+=query(tree[i].ls,l,mid,L,R))%=mod;
    }
    if(R>mid)
    {
        (ret+=query(tree[i].rs,mid+1,r,L,R))%=mod;
    }
    return ret;
}
void update(long long &i,long long l,long long r,long long L,long long R,long long v1,long long v2)
{
    if(!i)
    {
        i=++tot;
    }
    pushdown(i,l,r);
    if(L<=l&&r<=R)
    {
        (tree[i].A1+=(l-L)*v2%mod+v1)%=mod;
        (tree[i].d+=v2)%=mod;
        return;
    }
    long long mid=l+r>>1;
    if(L<=mid)
    {
        update(tree[i].ls,l,mid,L,R,v1,v2);
    }
    if(R>mid)
    {
        update(tree[i].rs,mid+1,r,L,R,v1,v2);
    }
    pushdown(tree[i].ls,l,mid);
    pushdown(tree[i].rs,mid+1,r);
    tree[i].sum=(tree[tree[i].ls].sum+tree[tree[i].rs].sum)%mod;
}
int main()
{
    n=read();
    for(long long i=1;i<=n;i++)
    {
        s[i]=read();
        (ans+=s[i])%=mod;
        l[i]=read();
        r[i]=read();
        long long temp=ksm(r[i]-l[i]+1,mod-2);
        (ans+=query(root,0,1000000000,l[i],r[i])*temp%mod*s[i]%mod)%=mod;
        update(root,0,1000000000,l[i],r[i],temp,temp);
        update(root,0,1000000000,r[i]+1,1000000000,1,0);
    }
    for(long long i=0;i<=tot;i++)
    {
        tree[i].A1=tree[i].d=tree[i].rs=tree[i].ls=tree[i].sum=0;
    }
    tot=0;
    root=0;
    for(long long i=n;i>=1;i--)
    {
        long long temp=ksm(r[i]-l[i]+1,mod-2);
        (ans+=query(root,0,1000000000,l[i],r[i])*temp%mod*s[i]%mod)%=mod;
        update(root,0,1000000000,l[i],r[i],0,temp);
        update(root,0,1000000000,r[i]+1,1000000000,1,0);
    }
    printf("%lld\n",ans);
    return 0;
}
带权排序

 

posted @ 2020-08-04 19:51  QDK_Storm  阅读(180)  评论(0编辑  收藏  举报