码迷,mamicode.com
首页 > 其他好文 > 详细

Codeforces Round #510 (Div. 2) D. Petya and Array (权值线段树)

时间:2018-09-17 21:30:35      阅读:315      评论:0      收藏:0      [点我收藏+]

标签:amp   使用权   long   can   lse   离散   scanf   解决   print   

题目地址:http://codeforces.com/contest/1042/problem/D

题意:给你n个数,问有多少个区间的和的值小于t

分析:区间和问题,常常用到前缀和来进行预处理,所以先预处理出前缀和数组sum

           sum[i]代表前i个数的和,那么sum[i]的贡献就是,  当i<k<=n时,存在多少个k,使sum[k]<t+sum[i]

           也就是求在[i+1,n]中,小于t+sum[i]的数有多少。

           所以我们可以类比于询问一个数是区间第几大的方法,使用权值线段树来解决,这里因为数的范围较大,首先需要进行离散化处理。

 

代码如下:

#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <iostream>
#include <vector>
#include <cstring>
#include <map>
using namespace std;
const int N=2e5+100;
typedef long long LL;
vector<LL>V;
int T[N<<3];
LL res;
LL sum[N];
LL a[N];
LL n,t;

int get_id(LL x)  //离散化处理
{
  return lower_bound(V.begin(),V.end(),x)-V.begin()+1;
}

void BuildTree(int rt,int l,int r)
{
  T[rt]=0;
  if(l==r)return;
  int mid=(l+r)>>1;
  BuildTree(rt<<1,l,mid);
  BuildTree(rt<<1|1,mid+1,r);
}

void Updata(int p,int v,int rt,int l,int r)  //插入v个值为p的数,若v为负数,即为删去.
{
  T[rt]+=v;
  if(l==r)return;
  int mid=(l+r)>>1;
  if(p<=mid)Updata(p,v,rt<<1,l,mid);
  else Updata(p,v,rt<<1|1,mid+1,r);
}


void less_num(int pos,int rt,int l,int r)
{
   if(l==r)
   return;
   int mid=(l+r)>>1;
   if(pos<=mid)
   less_num(pos,rt<<1,l,mid);
   else
   {
     res+=T[rt<<1];
     less_num(pos,rt<<1|1,mid+1,r);
   }
}



int main()
{
    scanf("%lld%lld",&n,&t);
    for(int i=1;i<=n;i++)
    {
      scanf("%lld",&a[i]);
      sum[i]=sum[i-1]+a[i];
      V.push_back(sum[i]);
    }
    if(n==1)
    {
        if(a[1]<t)
        printf("1\n");
        else
        printf("0\n");
        return 0;
    }
    for(int i=1;i<=n;i++)
    {
      LL x=sum[i]+t;
      V.push_back(x);
    }
    sort(V.begin(),V.end());
    V.erase(unique(V.begin(),V.end()),V.end());
    int len=V.size();
    BuildTree(1,1,len);
    Updata(get_id(sum[n]),1,1,1,len);
    for(int i=n-1;i>=0;i--)
    {
       LL x=sum[i]+t;
       less_num(get_id(x),1,1,len);
       if(i>0)
       Updata(get_id(sum[i]),1,1,1,len);
    }
    printf("%lld\n",res);
    return 0;
}

 

Codeforces Round #510 (Div. 2) D. Petya and Array (权值线段树)

标签:amp   使用权   long   can   lse   离散   scanf   解决   print   

原文地址:https://www.cnblogs.com/a249189046/p/9664895.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!