HDU6464 (权值线段树)-(查找区间第k1小于第k2小之间的和)

Posted shuaihui520

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU6464 (权值线段树)-(查找区间第k1小于第k2小之间的和)相关的知识,希望对你有一定的参考价值。

http://acm.hdu.edu.cn/showproblem.php?pid=6464

不理解先看博客:https://blog.csdn.net/g21glf/article/details/82986968

已知一开始有一个空序列,接下来有Q次操作,每次操作给出type、first和second三个值。当type为1时,意味着该操作属于第一种操作:往序列尾部添加first个second数。当type为2时,意味着该操作属于第二种操作:查询序列中第first小至第second小的数值之和(一共有(second - first + 1)个数被累加),并将结果对1000000007取模后输出。

技术图片
#include<bits/stdc++.h>
using namespace std ;
#define ll long long
const ll inf=1e16;
const ll mod=1e9+7;
const int maxn=1e5+50;

ll sum[maxn*40],val[maxn*40];
int ls[maxn*40],rs[maxn*40];
int cnt;
void update(int &o , int l , int r , ll  k , ll num)///建树的过程
{
    if(!o)
    o=++cnt;
    sum[o]+=k;
    val[o]+=1LL*k*num;///作为记录全部小于k 的数的和
    val[o]%=mod;
    if(l==r) return ; //到底就返回
    int mid=(l+r)/2;
    if(num<=mid)///在左子树
    update(ls[o] , l , mid , k , num);
    else
    update(rs[o] , mid+1 , r , k , num);
}

ll query(int o , int l , int r , ll k)
{
    if(l==r) return 1LL*k*l%mod;///这里与单纯找第k小不一样o(原理差不多 , 搜索到l 后 乘数量k)
    int mid=(l+r)/2;
    ll ans=0;
    if(k > sum[ls[o]]) /// 想找的数在右子树,前面有v个小于k的数 , 则找右子树第k-v小的数
    {
        ans=(val[ls[o]] + query(rs[o] , mid+1 , r , k-sum[ls[o]]))%mod;
    }
    else
        ans=query(ls[o],l,mid,k);
    return ans%mod;
}
int main()
{
    int Q,rt=0;
    scanf("%d",&Q);
    while(Q--)
    {
        int op;
        ll l , r;
        scanf("%d%lld%lld",&op,&l,&r);
        if(op==1) update(rt , 0 ,1e9 , l , r);
        else
        {
            ///查找小于r的全部数和于 查找小于l-1的全部数和
            ll ans=(query(rt , 0 , 1e9 , r) - query(rt,0,1e9 , l-1) + mod)%mod;
            printf("%lld
",ans);
        }
    }
}
View Code

 

以上是关于HDU6464 (权值线段树)-(查找区间第k1小于第k2小之间的和)的主要内容,如果未能解决你的问题,请参考以下文章

hdu6464 线段树

HDU6621 K-th Closest Distance 第 k 小绝对值(主席树(统计范围的数有多少个)+ 二分 || 权值线段树+二分)

主席树(区间第k小)

[学习笔记]主席树

HDU 2665.Kth number-无修改区间第K小-可持久化线段树(主席树)模板

权值线段与主席树总结