zoukankan      html  css  js  c++  java
  • 字节跳动-文远知行杯广东工业大学第十四届程序设计竞赛 1004 免费送气球(离散化+线段树)

    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 ", 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
     
    思路:
    每次1操作会往序列底加first个second,first 和 second 都是最大1e9的数据,每次2操作询问序列中第first到第second个数的和
    一开始就感觉有点像线段树,输入数据太大我们可以离线处理把数据离散化下,然后扔到线段树上,维护两个数组:
    sum: 区间数的值的和  num: 区间数的数量和  ,对于每次询问的first和second,我们找到第first个和第second个分别是哪两个数字,
    如果两个数字不相同,那么就先算出分别取了多少个这两个数字,对于两个数字中间的数字和我们可以直接用线段树区间求和得到
     
    感觉应该有更简单的写法,不过一开始思路就往线段树上偏了,干脆直接用线段树写了。。。。。。
    实现代码:
    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1
    #define mid ll m = (l + r) >> 1
    const ll mod = 1000000007;
    const ll M = 2e5+10;
    ll sum[M<<2],num[M<<2],b[M],op[M],vis[M ];
    struct node{
        ll x,y;
    }a[M];
    void update(ll p,ll c,ll l,ll r,ll rt){
         if(l == r){
            sum[rt] = (sum[rt]+(b[p]*c)%mod)%mod;
            num[rt] += c;
            return ;
         }
         mid;
         if(p <= m) update(p,c,lson);
         else update(p,c,rson);
         sum[rt] = (sum[rt<<1] + sum[rt<<1|1])%mod;
         num[rt] = num[rt<<1] + num[rt<<1|1];
    }
    
    ll ask(ll L,ll R,ll l,ll r,ll rt){  //求区间[L,R]的区间和
        if(L <= l&&R >= r){
            return sum[rt];
        }
        mid;
        ll ret = 0;
        if(L <= m) ret = (ret + ask(L,R,lson))%mod;
        if(R > m) ret = (ret + ask(L,R,rson))%mod;
        return ret;
    }
    
    ll ask1(ll p,ll l,ll r,ll rt){  //寻找序列中第p个是那个数字
        if(num[rt] >= p&& num[rt] - vis[r] < p){
            return r;
        }
        mid;
        if(p <= num[rt<<1]) ask1(p,lson);
        else ask1(p-num[rt<<1],rson);
    }
    
    ll ask2(ll L,ll R,ll l,ll r,ll rt){  //求区间[L,R]中有多少个数字
        if(L <= l&&R >= r){
            return num[rt];
        }
        mid;
        ll ret = 0;
        if(L <= m) ret += ask2(L,R,lson);
        if(R > m) ret += ask2(L,R,rson);
        return ret;
    }
    
    int main()
    {
        ll n,cnt = 0;
        cin>>n;
        for(ll i = 1;i <= n;i ++){
            cin>>op[i]>>a[i].x >> a[i].y;
            if(op[i] == 1) b[++cnt] = a[i].y;
        }
        sort(b+1,b+1+cnt);
        for(ll i = 1;i <= n;i ++){
            if(op[i] == 1){
                ll id = lower_bound(b+1,b+1+cnt,a[i].y)-b;
                update(id,a[i].x,1,cnt,1);
                vis[id] += a[i].x;
            }
            else{
                ll l = ask1(a[i].x,1,cnt,1);
                ll r = ask1(a[i].y,1,cnt,1);
                if(l == r){
                    cout<<(b[l]*((a[i].y-a[i].x+1)%mod))%mod<<endl;
                }
                else{
                    ll l = ask1(a[i].x,1,cnt,1);
                    ll r = ask1(a[i].y,1,cnt,1);
                    ll k1 = (((ask2(1,l,1,cnt,1) - a[i].x+1)%mod)*b[l])%mod;
                    ll k2 = (((a[i].y - ask2(1,r-1,1,cnt,1))%mod)*b[r])%mod;
                    ll k = 0;
                    k = ask(l+1,r-1,1,cnt,1);
                    cout<<(k+k1+k2)%mod<<endl;
                }
            }
        }
    }
  • 相关阅读:
    mySQL 规格严格
    单点登录JASIG研究分析
    Liferay 5.1.1 安装与整合CAS
    使用 CAS 在 Tomcat 中实现单点登录
    单点登录JASIG研究分析
    Liferay 5.1.1 安装与整合CAS
    SSO(Single Signon) in Action
    使用 CAS 在 Tomcat 中实现单点登录
    Netbeans 插件模块(Plugin Module)的开发
    NetBeans 时事通讯(刊号 # 22 Aug 18, 2008)
  • 原文地址:https://www.cnblogs.com/kls123/p/10542573.html
Copyright © 2011-2022 走看看