正题
题目链接:https://www.luogu.com.cn/problem/P6619
题目大意
有火系战士和冰系战士有一个温度和一个战斗力,每次加入或删除一个战士,要求一个最大的kkk使得温度不低于kkk的火系战士战斗力和温度不高于kkk的冰系战士战斗力和的最小值最大。
解题思路
不考虑kkk的话,对于这个答案很好求,我们只要求一个位置使得前面减去后面的和最小即可。这个可用树状数组上二分即可求出其中位置。考虑如何求最大的kkk,我们就是要求该位置开始后面的第一个火系战士即可,定义它的前面一个位置的前面有www个火系战士,也就是求第w+1w+1w+1个,也可以用树状数组上二分解决。
时间复杂度O(nlogn)O(n\log n)O(nlogn)
codecodecode
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define lowbit(x) (x&-x)
using namespace std;
const int N=2e6+10;
int n,cnt,op[N],t[N],x[N],y[N];
int T,M,b[N],ti[N],tf[N],tn[N],sf;
void Change(int x,int ice,int fire,int p){while(x<=M){ti[x]+=ice;tf[x]+=fire;tn[x]+=p;x+=lowbit(x);}sf+=fire;return;
}
int Query(int x,int ice,int fire,int p){int ans=0;while(x){ans+=ice*ti[x]+fire*tf[x]+tn[x]*p;x-=lowbit(x);}return ans;
}
int Ask1(){int zf=0,zi=0,l=1,r=M;while(l<r){int mid=(l+r)>>1;if(zi+ti[mid]>sf-zf-tf[mid])r=mid;else l=mid+1,zi+=ti[mid],zf+=tf[mid];}return l;
}
int Ask2(int x){int l=1,r=M,sum=0;while(l<r){int mid=(l+r)>>1;if(tn[mid]+sum>=x)r=mid;else l=mid+1,sum+=tn[mid];}return l;
}
int Calc(int x)
{return min(Query(x,1,0,0),sf-Query(x-1,0,1,0));}
int main()
{scanf("%d",&n);for(int i=1;i<=n;i++){scanf("%d%d",&op[i],&t[i]);if(op[i]==1){scanf("%d%d",&x[i],&y[i]);b[++cnt]=x[i];}}T=(int)log(n)/log(2)+1;M=(1<<T);sort(b+1,b+1+cnt);cnt=unique(b+1,b+1+cnt)-b-1;for(int i=1;i<=n;i++){if(op[i]==1){ x[i]=lower_bound(b+1,b+1+cnt,x[i])-b;Change(x[i],(!t[i])*y[i],t[i]*y[i],t[i]);}else{int k=t[i];Change(x[k],-(!t[k])*y[k],-t[k]*y[k],-t[k]);}int a1=Ask1();a1=Query(a1-1,0,0,1);int b1=Calc(a1=Ask2(a1+1));if(!b1)printf("Peace\n");else printf("%d %d\n",b[a1],2*b1);}
}