牛客:Gambling Monster(权值线段树+离散化+离线)

题意:

作为一个赌徒,魏先生不仅擅长玩地主(纸牌游戏),而且还擅长使用道具。在房东那里,有一种道具叫双卡,我更喜欢叫它DC。在一轮中,如果我们使用DC,我们的分数将加倍。当然,每个DC只能使用一次,而且每轮最多只能使用一个DC。

现在,魏先生想问你一个Q(1<=Q<=10万)问题,每个问题给出两个整数T(1<=T<=2)和X,T和X的意义如下。

T=1:你从魏先生那里得到X(1<=X<=5)DC。

T=2:你进行一轮,得到X(| X |<=1000000000)分数(不含DC)。

对于每个问题,你应该给出一个整数S(你能得到的最高分数)。

道具的使用在每个问题是独立的,道具将在你开始任何一轮之前给予。换言之,对于问题i,你也可以在问题k(k<j<i)中给出的循环中使用问题j中给出的DC。

题解:

每个询问都是独立的,需要支持插入新数和求前K大数的和。考虑到数据范围,可以先对所有插入的数据做离散化,然后离线用权值线段树处理。

为了使答案最优,负数直接不考虑。比赛的时候压根没看到第二个Sample,用Treap树瞎搞了一下午,害

//事先对所有插入的正数离散化
//然后开一颗权值线段树
//每个节点维护区间内的数量之和和区间内的所有数的数量权值乘积和
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+100;
typedef long long ll;
struct node {
    int l,r;
    ll sum;
    ll cnt;
}segTree[maxn<<2];
struct query {
    int op;
    ll w;
}q[maxn];
ll t[maxn];
int n;
int dc;
int tot=0;
ll ans=0;
void build (int i,int l,int r) {
    segTree[i].l=l;
    segTree[i].r=r;
    if (l==r) {
        segTree[i].sum=0;
        segTree[i].cnt=0;
        return;
    }
    int mid=(l+r)>>1;
    build(i<<1,l,mid);
    build(i<<1|1,mid+1,r);
    segTree[i].sum=segTree[i<<1].sum+segTree[i<<1|1].sum;
    segTree[i].cnt=segTree[i<<1].cnt+segTree[i<<1|1].cnt;
} 
void up (int i,int p,ll v) {
    if (segTree[i].l==p&&segTree[i].r==p) {
        segTree[i].cnt+=v;
        segTree[i].sum+=t[p]*v;
        return;
    }
    int mid=(segTree[i].l+segTree[i].r)>>1;
    if (p<=mid) up(i<<1,p,v);
    if (p>mid) up(i<<1|1,p,v);
    segTree[i].sum=segTree[i<<1].sum+segTree[i<<1|1].sum;
    segTree[i].cnt=segTree[i<<1].cnt+segTree[i<<1|1].cnt;
}
ll query_cnt (int i,int l,int r) {
    if (segTree[i].l>=l&&segTree[i].r<=r) {    
        return segTree[i].cnt;
    }
    int mid=(segTree[i].l+segTree[i].r)>>1;
    ll ans=0;
    if (l<=mid)
        ans+=query_cnt(i<<1,l,r);
    if (r>mid)
        ans+=query_cnt(i<<1|1,l,r);
    return ans;
}
ll query_sum (int i,int l,int r) {
    if (segTree[i].l>=l&&segTree[i].r<=r) {    
        return segTree[i].sum;
    }
    int mid=(segTree[i].l+segTree[i].r)>>1;
    ll ans=0;
    if (l<=mid)
        ans+=query_sum(i<<1,l,r);
    if (r>mid)
        ans+=query_sum(i<<1|1,l,r);
    return ans;
}

int main () {
    scanf("%d",&n);
    for (int i=1;i<=n;i++) {
        scanf("%d%lld",&q[i].op,&q[i].w);
        if (q[i].op==2) t[++tot]=q[i].w;
    } 
    sort(t+1,t+tot+1);
    int m=unique(t+1,t+tot+1)-t-1;
    build(1,1,m);
    for (int i=1;i<=n;i++) {
        int op=q[i].op;
        ll w=q[i].w;
        int u=-1;
        if (op==1) {
            dc+=w;
            int k=min((ll)dc,query_cnt(1,1,m));
            int l=1,r=m;
            while (l<=r) {
                int mid=(l+r)>>1;
                if (query_cnt(1,mid,m)>=k) {
                    u=mid;
                    l=mid+1;
                }
                else {
                    r=mid-1;
                }
            }
            ll tt=query_cnt(1,u+1,m);
            printf("%lld\n",ans+query_sum(1,u+1,m)+t[u]*(k-tt));
        }
        else {
            ans+=w;
            if (w>0) {
                int p=upper_bound(t+1,t+m+1,w)-t-1;
                up(1,p,1);
            }
            int k=min((ll)dc,query_cnt(1,1,m));
            int l=1,r=m;
            while (l<=r) {
                int mid=(l+r)>>1;
                if (query_cnt(1,mid,m)>=k) {
                    u=mid;
                    l=mid+1;
                }
                else {
                    r=mid-1;
                }
            }
            ll tt=query_cnt(1,u+1,m);
            printf("%lld\n",ans+query_sum(1,u+1,m)+t[u]*(k-tt));
        }
    }
}

 

posted @ 2020-09-14 19:29  zlc0405  阅读(185)  评论(0编辑  收藏  举报