其他分享
首页 > 其他分享> > Luogu P2839 [国家集训队]middle

Luogu P2839 [国家集训队]middle

作者:互联网

首先 [b,c] 是必选的, 然后选一段 [a,b) 的后缀和一段 (c,d] 的前缀(都可空)。

对于中位数(这里中位数采用这道题的定义)有个常见的处理方式: 二分 mid, 将 <mid 的设为 -1, 其余设为 1, 求总和, 若总和 >0, 则说明 ≥mid 的占到了一半以上, 即中位数 ≥mid。

采用这种处理方式, 二分中位数, 由于要中位数尽量大, 所以要贪心, 选后缀和前缀使得大于等于 mid 的减去小于等于 mid 的最大。

可以用可持久化线段树, 具体地, 类似笛卡尔树, 从小到大插入元素, 找出最大的前缀和后缀, 是可并信息, 可做。

#include<bits/stdc++.h>

using namespace std;

const int N = 2e4 + 23, SZ = 17 * 2e4 + 233;

int n;
struct Seq { int i, a; } seq[N];
bool cmp(Seq s1, Seq s2) { return s1.a > s2.a; }

struct dat {
	int siz, all, mxpre, mxsuf;
	dat(int sz, int a, int p, int s) : siz(sz), all(a), mxpre(p), mxsuf(s) {
	}
	dat() {
	}
} t[SZ];
dat mg(dat lef, dat rig) {
	return dat(  lef.siz + rig.siz, lef.all + rig.all, max(lef.mxpre, lef.all + rig.mxpre), max(rig.mxsuf, rig.all + lef.mxsuf)  );
}

int tot, Root[N], ls[SZ], rs[SZ];

void ins(int p, int &q, int l, int r, int x) {
	q = ++tot;
	if(l == r)
		{ t[q] = dat(1, 1, 1, 1); return;}
	ls[q] = ls[p], rs[q] = rs[p];
	int mid = (l+r) >> 1;
		if(x<=mid)
			ins(ls[p], ls[q], l, mid, x);
		else
			ins(rs[p], rs[q], mid+1, r, x);
	t[q] = mg((ls[q]?t[ls[q]]:dat(mid-l+1,-(mid-l+1),0,0)), (rs[q]?t[rs[q]]:dat(r-mid,-(r-mid),0,0)));
}

dat ask(int me, int l, int r, int x, int y) {
	if(x<=l && r<=y) return (me ? t[me] : dat(r-l+1, -(r-l+1), 0, 0));
		int mid = (l+r) >> 1;
	if(x<=mid && y>mid) return mg(ask(ls[me], l, mid, x, y), ask(rs[me], mid+1, r, x, y));
	if(x<=mid) return ask(ls[me], l, mid, x, y);
	if(y>mid) return ask(rs[me], mid+1, r, x, y);
}

bool chk(int mid, int a, int b, int c, int d) {
	int base = ask(Root[mid], 1, n, b, c).all + ask(Root[mid], 1, n, a, b-1).mxsuf + ask(Root[mid], 1, n, c+1, d).mxpre;
	return base >= 0;
}

int sol(int a, int b, int c, int d) {
	int l=1, r=n;
	while(l!=r) {
		int mid = (l+r) >> 1;
		chk(mid, a, b, c, d) ? r=mid : l=mid+1;
	}
	return seq[l].a;
}

int main()
{
	scanf("%d", &n);
	for(int i=1; i<=n; ++i) scanf("%d", &seq[i].a), seq[i].i = i;
	sort(seq+1, seq+1+n, cmp);
	for(int i=1; i<=n; ++i) ins(Root[i-1], Root[i], 1, n, seq[i].i);
	int Q;
	scanf("%d", &Q);
	int q[4] = {0}, las = 0;
	while(Q--)
	{
		for(int i=0; i<4; ++i) { scanf("%d", &q[i]); q[i] = (q[i] + las) % n + 1; }
		sort(q, q+4);
		las = sol(q[0], q[1], q[2], q[3]);
		cout << las << '\n';
	}
	return 0;
}

标签:return,lef,int,Luogu,mid,dat,middle,ask,国家集训队
来源: https://www.cnblogs.com/tztqwq/p/14301472.html