Petya and Array(权值线段树)

Petya and Array(luogu)

Description

求有多少个区间[l,r][l,r][l,r满足sum[l,r]<t

n<200000,|di|<1e9,t<2e14

Solution

权值线段树为l,r表示权值的线段树,相当于对桶进行线段树操作,

更形象一点,可称为值域线段树

设a数组为前缀和

则满足条件的[l,r]符合a[r]-a[l-1]<t,

即a[r]<t+a[l-1]

由于数据太大,先离散(怎么离散不妨自己想一想,注意考虑a[0])

然后从后往前扫一遍,加入a[i],再用线段树统计它贡献的答案

Code

#include <cstdio>
#include <cstdlib>
#include <algorithm>
#define ll long long
using namespace std;
const int N=2e5+10;
struct node
{
    ll v;
    int id;
    bool operator <(const node &o)const
    {
        return v<o.v;
    }
}a[N*2];
struct mode
{
    int l,r,lc,rc;
    ll sum;
}f[N*4];
int n,cnt,tot,rt;
ll d[N*2],t,ans;
void build(int l,int r,int &g)
{
    g=++tot;
    f[g].l=l,f[g].r=r;
    if(l==r) return ;
    int mid=(l+r)>>1;
    build(l,mid,f[g].lc);
    build(mid+1,r,f[g].rc);
}
void push_up(int g)
{
    f[g].sum=f[f[g].lc].sum+f[f[g].rc].sum;
}
void add(int g,int x)
{
    if(f[g].l==f[g].r) f[g].sum++;
    else
    {
        int mid=(f[g].l+f[g].r)>>1;
        if(x<=mid) add(f[g].lc,x);
        else add(f[g].rc,x);
        push_up(g);
    }
}
ll get(int g,int l,int r)
{
    if(l>r) return 0;
    if(f[g].l>=l && f[g].r<=r)
        return f[g].sum;
    int mid=(f[g].l+f[g].r)>>1;
    if(r<=mid) return get(f[g].lc,l,r);
    else if(l>mid) return get(f[g].rc,l,r);
    else return get(f[g].lc,l,mid)+get(f[g].rc,mid+1,r);
}
int main()
{
    scanf("%d%lld",&n,&t);
    n++;
    for(int i=1;i<=n;i++)
    {
        if(i>1) scanf("%lld",&a[i].v);
        else a[i].v=0;
        a[i].v+=a[i-1].v,a[i+n].v=a[i].v+t;
        a[i].id=i,a[i+n].id=i+n;
    }
    sort(a+1,a+n*2+1);
    for(int i=1;i<=n*2;i++)
    {
        if(i==1 || a[i].v!=a[i-1].v) cnt++;
        d[a[i].id]=cnt;
    }
    build(1,cnt,rt);
    for(int i=n;i>1;i--)
    {
        add(rt,d[i]);
        ans+=get(rt,1,d[i-1+n]-1);
    }
    printf("%lld\n",ans);
    return 0;
}

 

](ssum

求有多少对l,rl,r满足\sum_l^ra_i < t∑lr​ai​<t

上一篇:CF思维联系– CodeForces - 991C Candies(二分)


下一篇:G. Petya and Graph(经典项目与项目消耗问题)(网络流)