• [线段树] Jzoj P5232 带权排序


    Description

     

    Input

    输入文件名为sort.in。
    第一行包含一个整数n。
    接下来n行,每行三个整数si,li,ri,表示Ai的值为[li,ri] 中的随机整数。

    Output

    输出文件名为sort.out。
    输出一个整数,表示答案。
     

    Sample Input

    输入1:
    4
    1 2 3
    4 4 6
    2 0 5
    3 2 6
    
    输入2:
    10
    53736 68 512
    82493 870 920
    77300 206 576
    63900 4 565
    68675 0 488
    13610 4 922
    57472 614 825
    37474 394 970
    51896 398 766
    77136 656 723

    Sample Output

    输出1:
    650000033
    
    输出2:
    743178372
     

    Data Constraint

    对于20%的数据,n<=6,0<=li<=ri<=15
    对于40%的数据,n<=10,0<=li<=ri<=20
    对于60%的数据,0<=li<=ri<=1000
    对于100%的数据,n<=10^5,0<=li<=ri<=10^9,0<=si<=10^9

    题解

    • 现在考虑如何求这个东东,可以发现pi的期望其实就是有多少人排在i前
    • 那么它对i后的点j选在[0...l-1]是没有贡献的,若在[l...r]中,贡献就是x-l[i]+1/r[i]-l[i]+1,若在[r...inf]中,贡献就是1
    • 每个贡献其实就是在平面直角坐标系中,就是三段线段,这三段线段其实都是就是一个等差数列
    • 那我们就可以考虑在线段树里加上一条直线,维护线段的首项,末项和公差
    • 然后正反做一遍,就好了

    代码

     1 #include <cstdio>
     2 #include <iostream>
     3 #include <cstring>
     4 #define ll long long
     5 using namespace std;
     6 const ll mo=1e9+7,N=100010,inf=1e9;
     7 struct edge{ll l,r,v,x,y;}tree[N*60];
     8 ll a[N],l[N],r[N],k[N],n,cnt,d,o,ans;
     9 ll ksm(ll a,ll b) 
    10 {
    11     ll r=1;
    12     for (;b;b>>=1,a=a*a%mo) if (b&1) r=r*a%mo; 
    13     return r;
    14 }
    15 void work(ll &d,ll l,ll r,ll L,ll R)
    16 {
    17     if (!d) d=++cnt;
    18     (tree[d].x+=L)%=mo,(tree[d].y+=R)%=mo,(tree[d].v+=(r-l+1)*R)%=mo;
    19     if ((l+r)&1) o=(r-l+1)/2*(r+l)%mo; else o=(r+l)/2*(r-l+1)%mo;
    20     (tree[d].v+=o*L)%=mo;
    21 }
    22 void down(ll d,ll l,ll r)
    23 {
    24     if (tree[d].x||tree[d].y)
    25     {
    26         ll mid=l+r>>1;
    27         work(tree[d].l,l,mid,tree[d].x,tree[d].y),work(tree[d].r,mid+1,r,tree[d].x,tree[d].y);
    28         tree[d].x=tree[d].y=0;
    29     }
    30 }
    31 void insert(ll &d,ll l,ll r,ll L,ll R,ll x,ll y)
    32 {
    33     if (R<l||L>r) return;
    34     if (!d) d=++cnt;
    35     if (L<=l&&r<=R) work(d,l,r,x,y);
    36     else 
    37     {
    38         ll mid=l+r>>1; down(d,l,r);
    39         insert(tree[d].l,l,mid,L,R,x,y),insert(tree[d].r,mid+1,r,L,R,x,y);
    40         tree[d].v=(tree[tree[d].l].v+tree[tree[d].r].v)%mo;
    41     }
    42 }
    43 ll Query(ll d,ll l,ll r,ll L,ll R)
    44 {
    45     if (R<l||L>r) return 0;
    46     if (L<=l&&r<=R) return tree[d].v;
    47     ll mid=l+r>>1; down(d,l,r);
    48     return (Query(tree[d].l,l,mid,L,R)+Query(tree[d].r,mid+1,r,L,R))%mo;
    49 }
    50 int main()
    51 {
    52     freopen("sort.in","r",stdin),freopen("sort.out","w",stdout);
    53     scanf("%lld",&n);
    54     for (ll i=1;i<=n;i++) scanf("%lld%lld%lld",&a[i],&l[i],&r[i]);
    55     for (ll i=1;i<=n;i++)
    56     {
    57         ll ny=ksm(r[i]-l[i]+1,mo-2);
    58         k[i]=Query(d,0,inf,l[i],r[i])*ny%mo;
    59         insert(d,0,inf,r[i]+1,inf,0,1),insert(d,0,inf,l[i],r[i],ny,(mo-(l[i]-1)*ny%mo)%mo);
    60     }
    61     d=0;
    62     for (ll i=1;i<=cnt;i++) tree[i].x=tree[i].y=tree[i].v=tree[i].l=tree[i].r=0;
    63     cnt=0;
    64     for (ll i=n;i;i--)
    65     {
    66         ll ny=ksm(r[i]-l[i]+1,mo-2);
    67         (k[i]+=Query(d,0,inf,l[i],r[i])*ny%mo)%=mo;
    68         insert(d,0,inf,r[i]+1,inf,0,1),insert(d,0,inf,l[i],r[i],ny,(mo-l[i]*ny%mo)%mo);
    69     }
    70     for (ll i=1;i<=n;i++) ans=(ans+(k[i]+1)*a[i])%mo;
    71     printf("%lld",ans);
    72 }
  • 相关阅读:
    线程
    开启程序子进程的方式
    multiprocess模块
    计算机网络小知识
    解决粘包问题
    网络编程相关
    反射与元类
    多态相关
    封装相关与接口
    类的继承和组合
  • 原文地址:https://www.cnblogs.com/Comfortable/p/10311390.html
Copyright © 2020-2023  润新知