用户工具

站点工具


2020-2021:teams:wangzai_milk:20200806比赛记录

这是本文档旧的修订版!


2020.08.06codeforces加训

比赛情况

题号 A B C D E F G H I J
状态 O - O - - - O Ø O O

O 在比赛中通过 Ø 赛后通过 ! 尝试了但是失败了 - 没有尝试

比赛时间

2020-08-06 12:00-17:00

题解

A - Hacker Cups and Balls

题意:给定一个序列,给q次操作,每次操作升序或降序排列某区间中的数,问q次操作后序列中间位置的数是什么。

题解:

我们可以考虑二分答案,然后把所有大于当前二分出答案的数字赋值为1,其余的赋值为0,这样一次排序操作其实就是查询一个区间有多少个0多少个1,然后把前后两部分分别连续赋值为0和1,这样一个操作通过线段树就能完成。

然后查询中间位置的数字是0还是1,如果是1那么中位数就应该是更大,如果为0那么中位数就可能是当前答案或更小。

点击以显示 ⇲

点击以隐藏 ⇱

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5+5;
int tr[N<<2],lazy[N<<2],a[N];
struct Node {
	int l,r;
}q[N];
int midans,n,m;
void Push_Down(int p,int l,int r) {
	if (lazy[p]==-1||l==r)return;
	int mid = (l+r)>>1;
	tr[p<<1] = (mid-l+1)*lazy[p];
	tr[p<<1|1] = (r-mid)*lazy[p];
	lazy[p<<1] = lazy[p<<1|1] = lazy[p];
	lazy[p] = -1;
}
void Build(int p,int l,int r) {
	lazy[p] = -1;
	if (l==r) {
		tr[p] = a[l] > midans;
		return;
	}
	int mid = (l+r)>>1;
	Build(p<<1,l,mid);
	Build(p<<1|1,mid+1,r);
	tr[p] = tr[p<<1]+tr[p<<1|1];
}
void Update(int p,int l,int r,int a,int b,int c) {
	if (a > b) return;
	Push_Down(p,l,r);
	if (l >= a && r <= b) {
		tr[p] = (r-l+1)*c;
		lazy[p] = c;
		return;
	}
	int mid = (l+r)>>1;
	if (a <= mid) Update(p<<1,l,mid,a,b,c);
	if (b > mid) Update(p<<1|1,mid+1,r,a,b,c);
	tr[p] = tr[p<<1] + tr[p<<1|1];
}
int Getans(int p,int l,int r,int a,int b) {
	Push_Down(p,l,r);
	if (l >= a && r <= b) return tr[p];
	int ans = 0;
	int mid = (l+r)>>1;
	if (a <= mid) ans+= Getans(p<<1,l,mid,a,b);
	if (b > mid) ans+= Getans(p<<1|1,mid+1,r,a,b);
	return ans;
}
bool check(int x) {
	midans = x;
	Build(1,1,n);
	for (int i = 1;i<= m;i++) {
		int L = min(q[i].l,q[i].r);
		int R = max(q[i].l,q[i].r);
		int tmp = Getans(1,1,n,L,R);
		if (q[i].l < q[i].r) {
			Update(1,1,n,L,R-tmp,0);
			Update(1,1,n,R-tmp+1,R,1);
		} else {
			Update(1,1,n,L,L+tmp-1,1);
			Update(1,1,n,L+tmp,R,0);
		}
	}
	int midpos = (n>>1)+1;
	int t = Getans(1,1,n,midpos,midpos);
	return t == 1;
}
int GetFinalans() {
	int l = 1,r = n+1;
	while (l < r) {
		int mid = (l+r)>>1;
		if (check(mid))l = mid+1;
		else r = mid;
	}
	return l;
}
int main()
{
	scanf("%d%d",&n,&m);
	for (int i = 1;i<= n;i++)scanf("%d",&a[i]);
	for (int i = 1;i<= m;i++)
		scanf("%d%d",&q[i].l,&q[i].r);
	printf("%d\n",GetFinalans());
	return 0;
}

比赛总结与反思

2020-2021/teams/wangzai_milk/20200806比赛记录.1596723103.txt.gz · 最后更改: 2020/08/06 22:11 由 infinity37