• 偏序+线段树——cf1320C


    挺好的题

    /*
    每个武器攻击力ai,价格cai
    每个装备防御力bi,价格cbi
    每只怪兽攻击力xi,防御力yi,收益zi
        ai>yi && bi>xi 那么可以获得收益zi 
    选择一件武器,一件装备,求最大收益 
    
    武器装备按ai,bi升序排序
    怪兽按yi升序排序,那么当遍历到第i、只怪兽时,只有aj>yi+1的武器才有用,贪心从[j,n]里找最便宜的武器
    对于防具,只有bk>xi+1的防具才有用,但是不能保证bk>xi-1(因为是按yi升序排序的),所以转换成这只怪兽可以被多少防具防御
        开线段树维护一下贡献,每次查询后更新一次ans 
    */
    #include<bits/stdc++.h>
    using namespace std;
    #define N 200005
    #define ll long long 
    
    struct A{ll a,c;}a[N];
    struct B{ll b,c;}b[N];
    struct D{ll x,y,z;}d[N];
    int cmp1(A a,A b){return a.a<b.a;}
    int cmp2(B a,B b){return a.b<b.b;}
    int cmp3(D a,D b){return a.x<b.x;}
    ll n,m,p,suf[N];//suf[i]表示[i+1,m]里装备最便宜的 
    
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1
    ll Max[N<<2],lazy[N<<2];
    void build(int l,int r,int rt){
        if(l==r){Max[rt]=-b[l].c;return;}
        int m=l+r>>1;
        build(lson);
        build(rson);
        Max[rt]=max(Max[rt<<1],Max[rt<<1|1]);
    }
    void pushdown(int rt){
        if(lazy[rt]){
            lazy[rt<<1]+=lazy[rt];
            lazy[rt<<1|1]+=lazy[rt];
            Max[rt<<1]+=lazy[rt];
            Max[rt<<1|1]+=lazy[rt];
            lazy[rt]=0;
        }
    }
    void update(int L,int R,ll v,int l,int r,int rt){
        if(L<=l && R>=r){lazy[rt]+=v;Max[rt]+=v;return;}
        pushdown(rt);
        int m=l+r>>1;
        if(L<=m)update(L,R,v,lson);
        if(R>m)update(L,R,v,rson);
        Max[rt]=max(Max[rt<<1],Max[rt<<1|1]); 
    }
    
    int main(){
        cin>>n>>m>>p;
        for(int i=1;i<=n;i++)scanf("%lld%lld",&a[i].a,&a[i].c);
        for(int i=1;i<=m;i++)scanf("%lld%lld",&b[i].b,&b[i].c);
        for(int i=1;i<=p;i++)scanf("%lld%lld%lld",&d[i].x,&d[i].y,&d[i].z);
        sort(a+1,a+1+n,cmp1);
        sort(b+1,b+1+m,cmp2);
        sort(d+1,d+1+p,cmp3);
        suf[n]=a[n].c;
        for(int i=n-1;i>=1;i--)
            suf[i]=min(suf[i+1],a[i].c);
        
        build(1,m,1);
        ll ans=-a[1].c-b[1].c;
        int pos1=1,pos2=1;
        for(int i=1;i<=p;i++){//按x从小到大枚举d[i] 
            ll X=d[i].x+1,Y=d[i].y+1;
            while(pos1<=n && a[pos1].a<X)pos1++;
            if(pos1==n+1)break;
            
            pos2=-1;
            int L=1,R=m,mid;
            while(L<=R){
                mid=L+R>>1;
                if(b[mid].b>=Y)
                    R=mid-1,pos2=mid;
                else L=mid+1;
            }
            if(pos2>0 && pos2<=m)
                update(pos2,m,d[i].z,1,m,1);
            ans=max(ans,Max[1]-suf[pos1]);
        }
        
        cout<<ans<<'
    ';
    } 
  • 相关阅读:
    java 单向链表实现
    super、this
    Java程序员们最常犯的10个错误
    Codeforces-1323D Present
    Codeforces-1323E Instant Noodles
    Codeforces-1312E Array Shrinking
    Codeforces-1327D Infinite Path
    Codeforces-1326D Prefix-Suffix Palindrome
    HDU-5885 XM Reserves
    NTT(快速数论变换)用到的各种素数及原根
  • 原文地址:https://www.cnblogs.com/zsben991126/p/12470456.html
Copyright © 2020-2023  润新知