偏序+线段树——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<<'\n'; }