• E. Two Types of Spells(根据位置选取前k大总和)


    题:https://codeforces.com/contest/1398/problem/E

    题意:有俩种攻击类型,第一种为tp=0的攻击,只造成d[i]的伤害,第二种为tp=1的攻击,造成d[i]的伤害同时使下次攻击造成的伤害值加倍。当d[i]>0时表示学习了此技能,否则表示忘记了此技能,问n次操作每次操作后能造成的最大伤害值是多少。

    分析:其实只要考虑加倍哪些就行,那么当然,肯定使加倍前k个大的(k这里是指由k个tp=1类型的技能),此外若前k个大的全是tp=1,那么肯定至少有一个没有加倍到,那么对于这种情况,我们每次统计时只要把tp=1攻击造成伤害值最小的去掉,然后计算出前k大的和即可,用线段树维护sum(区间和,没有tp的区别),num1(全部攻击的个数,没有tp的区别),num2(tp==1的个数)

    #include<bits/stdc++.h>
    using namespace std;
    #define lson root<<1,l,midd
    #define rson root<<1|1,midd+1,r
    #define pb push_back
    #define ull unsigned long long
    #define pii pair<int,int>
    #define MP make_pair
    typedef long long ll;
    const ll INF=1e18;
    const int inf=0x3f3f3f3f;
    const int M=1e6+6;
    struct node{
        ll sum,num1,num2;
    }tr[M<<2];
    int tp[M];
    ll tmp[M],d[M];
    void build(int root,int l,int r){
        tr[root].sum=tr[root].num1=tr[root].num2=0;
        if(l==r)
            return ;
        int midd=(l+r)>>1;
        build(lson);
        build(rson);
    }
    void up(int root){
        tr[root].sum=tr[root<<1].sum+tr[root<<1|1].sum;
        tr[root].num1=tr[root<<1].num1+tr[root<<1|1].num1;
        tr[root].num2=tr[root<<1].num2+tr[root<<1|1].num2;
    }
    void update(int pos,ll v1,ll v2,int root,int l,int r){
        if(l==r){
            tr[root].sum+=v1*tmp[l];
            tr[root].num1+=v1;
            tr[root].num2+=v2;
            return ;
        }
        int midd=(l+r)>>1;
        if(pos<=midd)
            update(pos,v1,v2,lson);
        else
            update(pos,v1,v2,rson);
        up(root);
    }
    int querymin(int root,int l,int r){
        if(l==r)
            return l;
        int midd=(l+r)>>1;
        if(tr[root<<1].num2)
            return querymin(lson);
        else
            return querymin(rson);
    }
    ll querysum(int k,int root,int l,int r){
        if(k==0)
            return 0;
        if(tr[root].num1<=k)
            return tr[root].sum;
        if(l==r)
            return 1ll*k*tmp[l];
        int midd=(l+r)>>1;
        if(tr[root<<1|1].num1>=k)
            return querysum(k,rson);
        else
            return tr[root<<1|1].sum+querysum(k-tr[root<<1|1].num1,lson);
    }
    int main(){
        int n;
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            scanf("%d%lld",&tp[i],&d[i]),tmp[i]=abs(d[i]);
        sort(tmp+1,tmp+1+n);
        int light=0;
        int m=unique(tmp+1,tmp+1+n)-tmp-1;
        build(1,1,m);
        for(int i=1;i<=n;i++){
            int pos=lower_bound(tmp+1,tmp+1+m,abs(d[i]))-tmp;
            ll val1=1,val2=0;
            if(d[i]<0)
                val1=-1;
            if(tp[i]==1){
                if(d[i]<0)
                    val2=-1,light--;///light个数
                else
                    val2=1,light++;
            }
            update(pos,val1,val2,1,1,m);
            ll ans=tr[1].sum;
            if(light!=0){
                int minpos=querymin(1,1,m);
                update(minpos,-1,0,1,1,m);
                ans+=querysum(light,1,1,m);
                update(minpos,1,0,1,1,m);
            }
            printf("%lld
    ",ans);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    Xcode下 gdb 调试命令
    Xcode 获取本地IP
    Linux终端提示符PS1设置(颜色)
    linux 客户端 Socket 非阻塞connect编程
    关于SIGPIPE导致的程序退出
    jQuery MiniUI开发系列之:数据验证
    支持Java Spring MVC
    支持ASP.NET MVC
    支持ASP.NET WebService
    jQuery MiniUI开发系列之:Ajax处理超时、服务端错误
  • 原文地址:https://www.cnblogs.com/starve/p/13561665.html
Copyright © 2020-2023  润新知