HDU - 6464 免费送气球(线段树二分)(“字节跳动-文远知行杯”广东工业大学第十四届程序设计竞赛)

免费送气球

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 105    Accepted Submission(s): 15


 

Problem Description

又到了GDUT一年一度的程序设计竞赛校赛的时间啦。同学们只要参加校赛,并且每解出一道题目就可以免费获得由ACM协会和集训队送出的气球一个。听到这个消息,JMC也想参加免费拿气球。可是,由于JMC太菜了而被禁止参赛,于是他找到你想让你帮忙参加比赛,可以通过执行下面的C++程序解决问题后获得气球并送给他。JMC保证了下面的程序一定能获得正确的结果。

void solve(int Q, int type[], long long first[], long long second[]) {
    vector<long long> vec;
    for (int i = 0; i < Q; ++i) {
        if (type[i] == 1) {
            long long k = first[i], val = second[i];
            while (k--) {
                vec.push_back(val);
            }
        }
        else if (type[i] == 2) {
            sort(vec.begin(), vec.end());
            long long l = first[i] - 1, r = second[i], res = 0;
            while (l < r) {
                res = (res + vec[l++]) % 1000000007;
            }
            printf("%lld\n", res);
        }
    }
}


为防止你被JMC的代码搞到头晕目眩,JMC特意给出了问题的文字描述。已知一开始有一个空序列,接下来有Q次操作,每次操作给出type、first和second三个值。当type为1时,意味着该操作属于第一种操作:往序列尾部添加first个second数。当type为2时,意味着该操作属于第二种操作:查询序列中第first小至第second小的数值之和(一共有(second - first + 1)个数被累加),并将结果对1000000007取模后输出。

 

 

Input

单组数据
第一行一个Q(1 <= Q <= 1e5),代表Q次操作。
接下来有Q行,每行包含三个整数type、first和second;其中1 <= type <= 2。当type等于1时,0 <= first,second < 1e9。当type等于2时,1 <= first <= second,且first和second均不大于目前已添加进序列的数的数量。

 

 

Output

对于每次操作二,将结果对1000000007取模后输出。

 

 

Sample Input

 

6 1 5 1 1 6 3 2 2 5 2 4 8 1 2 2 2 4 8

 

 

Sample Output

 

4 11 9

 

 

Source

“字节跳动-文远知行杯”广东工业大学第十四届程序设计竞赛

 

 

 

题解:首先将所有将要添加的数离散化,然后建立两颗线段树,分别维护区间内数的数量和区间和。对于操 作一,根据离散化后的值在线段树对应位置添加 k 个 val,并维护线段树每一个节点所代表区间的和。 对于操作二,首先将问题转化成两个前 k 小之和的查询,具体做法:传入参数 k 搜索线段树,先递归 检查左子区间的数的数量,如果小于当前 k,再传入当前 k-'左子区间的数的数量'作为更新后的参数 k 递归搜索右子区间;递归搜索时,应将满足数量条件(当前区间的数的数量小于等于 k)等于的区间和 累加并返回作为答案。 

 

注意!数量那个线段树不能mod,因为会影响query的计算和判断!

#include <iostream>
#include <map>
#include <algorithm>
#include <vector>
using namespace std;
typedef long long ll;
#define mod 1000000007
#define MAXN 100005
#define N 100005

struct query1{
   ll t;
   ll f,s;
   query1(ll a,ll b,ll c){
       t=a;
       f=b;
       s=c;
   }
   query1(){}
}que[100005];

map<ll,ll> mp;
ll cnt=0;
ll sorted[100005];

ll num[MAXN<<2];
ll sum[MAXN<<2];
void pushup(ll rt){
    num[rt]=(num[rt<<1]+num[rt<<1|1]);
    sum[rt]=(sum[rt<<1]+sum[rt<<1|1])%mod;
}

void update(ll P,ll C,ll l,ll r,ll rt){
    if(l==r){
        num[rt]=(num[rt]+C);
        sum[rt]=(sum[rt]+mp[P]*C%mod)%mod;
        return;
    }

    ll m=(l+r)/2;

    if(P<=m)
        update(P,C,l,m,rt<<1);
    else
        update(P,C,m+1,r,rt<<1|1);
    pushup(rt);
}

ll query(ll K,ll l,ll r,ll rt){

    if(K==0)
        return 0;
    if(l==r){
       return K*mp[l]%mod;
    }

    ll m=(l+r)/2;
    if(num[rt<<1]>=K){
        return query(K,l,m,rt<<1)%mod;
    }
    else{
        return (sum[rt<<1]+query(K-num[rt<<1],m+1,r,rt<<1|1))%mod;
    }
}




int main()
{
    ll Q;
    scanf("%I64d",&Q);
    ll fir,sec;
    ll t;

    for(ll i=0;i<Q;i++){
        scanf("%I64d%I64d%I64d",&t,&fir,&sec);
        que[i]=query1(t,fir,sec);
        if(t==1)
            sorted[cnt++]=sec;
    }

    sort(sorted,sorted+cnt);
    map<ll,ll> pm;
    int cc=1;
    for(int i=0;i<cnt;i++){
        if(pm[sorted[i]]==0){
            pm[sorted[i]]=cc++;
            mp[cc-1]=sorted[i];
        }
    }

    for(ll i=0;i<Q;i++){
        if(que[i].t==1){
            update(pm[que[i].s],que[i].f,1,cnt,1);
        }
        else{
            ll a=query(que[i].f-1,1,cnt,1);
            ll b=query(que[i].s,1,cnt,1);
            printf("%I64d\n",(b-a+mod)%mod);
        }
    }


    return 0;
}

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值