Codeforces Round 995 (Div. 3)

ABC略

D

从小到大排序,枚举每个a对应的另一个数的范围,二分,找到另一个数的个数加和。答案就是这个和/2

E

最后的卖的价格一定是n个a和b中的一个,枚举所有a和b,然后判断不满意度是否<=k。只需建立一个线段树,让每个a+1~b都加一就能在logn知道选一个数的不满意度。由于a和b的范围,离散化即可

#include
#define int long long
using namespace std;
const int N=2e5+10;
int T,n,k,a[N],b[N],c[N*3],d[N*3],tot,e[N],ans;
struct Tree{
	int l,r,val;
}t[N*12];
void init()
{
	tot=ans=0;
	for(int i=1;i<=n*12;i++) t[i].val=0;
}
void build(int p,int l,int r)
{
	t[p].l=l,t[p].r=r;
	if(l==r) return ;
	int mid=(l+r)/2;
	build(p*2,l,mid);build(p*2+1,mid+1,r);
}
void add(int p,int l,int r)
{
	if(t[p].l>=l&&t[p].r<=r) {t[p].val++; return ;}
	int mid=(t[p].l+t[p].r)/2;
	if(l<=mid) add(p*2,l,r);
	if(r>mid) add(p*2+1,l,r);
}
int ask(int p,int k)
{
	int s=0;
	if(t[p].l==t[p].r&&t[p].l==k) return t[p].val;
	int mid=(t[p].l+t[p].r)/2;
	if(k<=mid) s+=ask(p*2,k);
	if(k>mid) s+=ask(p*2+1,k);
	return s+t[p].val;
}
void solve()
{
	cin>>n>>k;
	init();
	for(int i=1;i<=n;i++) cin>>a[i],c[i]=a[i]+1;
	for(int i=1;i<=n;i++) cin>>b[i],c[n+i]=b[i];
	for(int i=1;i<=n;i++) e[i]=b[i];
	sort(e+1,e+n+1);
	for(int i=1;i<=n;i++) c[2*n+i]=a[i];
	sort(c+1,c+3*n+1);
	for(int i=1;i<=3*n;i++)
	if(c[i]!=c[i-1]) d[++tot]=c[i];
	build(1,1,tot);
	for(int i=1;i<=n;i++)
	{
		int aa=lower_bound(d+1,d+tot+1,a[i]+1)-d,bb=lower_bound(d+1,d+tot+1,b[i])-d;
		add(1,aa,bb);
	}
	for(int i=1;i<=n;i++)
	{
		int aa=lower_bound(d+1,d+tot+1,a[i])-d,bb=lower_bound(d+1,d+tot+1,b[i])-d;
		if(ask(1,aa)<=k)
		{
			int aaa=lower_bound(e+1,e+n+1,a[i])-e;
			ans=max(ans,(n-aaa+1)*a[i]);
		}
		if(ask(1,bb)<=k)
		{
			int bbb=lower_bound(e+1,e+n+1,b[i])-e;
			ans=max(ans,(n-bbb+1)*b[i]);
		}
	}
	cout<>T;
	while(T--) solve();
}

这场第一次在实验室打的。E题的线段树数组开小了,忘了我离散的是a a+1 b,应该开N*12。玛德考完才发现

你可能感兴趣的:(算法)