middle BZOJ2653

 我们平时建立函数式线段树的顺序都是按照索引建立,值作为线段树的区间,此题我们要按值的顺序建立,将索引作为线段树的区间,又涨姿势了...

具体可以参考爱神的题解: http://blog.csdn.net/acm_cxlove/article/details/8566093


#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <queue>
#include <algorithm>
#include <vector>
#include <cstring>
#include <stack>
#include <cctype>
#include <utility>   
#include <map>
#include <string>  
#include <climits> 
#include <set>
#include <string>    
#include <sstream>
#include <utility>   
#include <ctime>
#include <bitset>

using std::priority_queue;
using std::vector;
using std::swap;
using std::stack;
using std::sort;
using std::max;
using std::min;
using std::pair;
using std::map;
using std::string;
using std::cin;
using std::cout;
using std::set;
using std::queue;
using std::string;
using std::stringstream;
using std::make_pair;
using std::getline;
using std::greater;
using std::endl;
using std::multimap;
using std::deque;
using std::unique;
using std::lower_bound;
using std::random_shuffle;
using std::bitset;
using std::upper_bound;
using std::multiset;

typedef long long LL;
typedef unsigned long long ULL;
typedef unsigned UN;
typedef pair<int, int> PAIR;
typedef multimap<int, int> MMAP;
typedef LL TY;
typedef long double LF;

const int MAXN(500010);
const int MAXM(50010);
const int MAXE(150010);
const int MAXK(6);
const int HSIZE(13131);
const int SIGMA_SIZE(4);
const int MAXH(20);
const int INFI((INT_MAX-1) >> 1);
const ULL BASE(31);
const LL LIM(1e13);
const int INV(-10000);
const int MOD(31313);
const double EPS(1e-7);
const LF PI(acos(-1.0));

template<typename T> inline void checkmax(T &a, T b){if(b > a) a = b;}
template<typename T> inline void checkmin(T &a, T b){if(b < a) a = b;}
template<typename T> inline T ABS(const T &a){return a < 0? -a: a;}

int ls[MAXN], rs[MAXN], sum[MAXN], lsum[MAXN], rsum[MAXN], root[20010], tab[20010];
int rear;

void push_up(int rt)
{
	sum[rt] = sum[ls[rt]]+sum[rs[rt]];
	lsum[rt] = max(lsum[ls[rt]], sum[ls[rt]]+lsum[rs[rt]]);
	rsum[rt] = max(rsum[rs[rt]], sum[rs[rt]]+rsum[ls[rt]]);
}

void build(int l, int r, int &rt)
{
	rt = rear++;
	if(l == r)
	{
		sum[rt] = lsum[rt] = rsum[rt] = 1;
		return;
	}
	int m = (l+r) >> 1;
	build(l, m, ls[rt]);
	build(m+1, r, rs[rt]);
	push_up(rt);
}

void updata(int l, int r, int val, int prt, int &rt)
{
	rt = rear++;
	ls[rt] = ls[prt];
	rs[rt] = rs[prt];
	if(l == r)
	{
		sum[rt] = lsum[rt] = rsum[rt] = -1;
		return;
	}
	int m = (l+r) >> 1;
	if(val <= m) updata(l, m, val, ls[prt], ls[rt]);
	else updata(m+1, r, val, rs[prt], rs[rt]);
	push_up(rt);
}

int query(int l, int r, int ql, int qr, int rt)
{
	if(ql <= l && qr >= r) return sum[rt];
	int m = (l+r) >> 1, ret = 0;
	if(ql <= m) ret = query(l, m, ql, qr, ls[rt]);
	if(qr > m) ret += query(m+1, r, ql, qr, rs[rt]);
	return ret;
}

int queryl(int l, int r, int ql, int qr, int rt)
{
	if(ql == l && qr == r) return lsum[rt];
	int m = (l+r) >> 1, ret;
	if(qr <= m) ret = queryl(l, m, ql, qr, ls[rt]);
	else if(ql > m) ret = queryl(m+1, r, ql, qr, rs[rt]);
	else ret = max(queryl(l, m, ql, m, ls[rt]), query(l, m, ql, m, ls[rt])+queryl(m+1, r, m+1, qr, rs[rt]));
	return ret;
}

int queryr(int l, int r, int ql, int qr, int rt)
{
	if(ql == l && qr == r) return rsum[rt];
	int m = (l+r) >> 1, ret;
	if(qr <= m) ret = queryr(l, m, ql, qr, ls[rt]);
	else if(ql > m) ret = queryr(m+1, r, ql, qr, rs[rt]);
	else ret = max(queryr(m+1, r, m+1, qr, rs[rt]), query(m+1, r, m+1, qr, rs[rt])+queryr(l, m, ql, m, ls[rt]));
	return ret;
}

int n;

bool check(int val, int a, int b, int c, int d)
{
	int temp = queryr(0, n-1, a, b, root[val-1]);
	if(b+1 < c) temp += query(0, n-1, b+1, c-1, root[val-1]);
	temp += queryl(0, n-1, c, d, root[val-1]);
	return temp >= 0;
}

PAIR arr[20010];
int q[4];

int main()
{
	while(~scanf("%d", &n))
	{
		for(int i = 0; i < n; ++i)
		{
			scanf("%d", tab+i);
			arr[i] = PAIR(tab[i], i);
		}
		sort(tab, tab+n);
		int tn = unique(tab, tab+n)-tab;
		for(int i = 0; i < n; ++i) arr[i].first = lower_bound(tab, tab+tn, arr[i].first)-tab+1;
		sort(arr, arr+n);
		rear = 0;
		build(0, n-1, root[0]);
		updata(0, n-1, arr[0].second, root[0], root[arr[0].first]);
		for(int i = 1; i < n; ++i) updata(0, n-1, arr[i].second, root[arr[i-1].first], root[arr[i].first]);
		int Q, ans = 0;
		scanf("%d", &Q);
		while(Q--)
		{
			scanf("%d%d%d%d", q, q+1, q+2, q+3);
			for(int i = 0; i < 4; ++i) q[i] = (q[i]+ans)%n;
			sort(q, q+4);
			int l = 1, r = tn+1;
			while(l < r)
			{
				int m = (l+r) >> 1;
				if(check(m, q[0], q[1], q[2], q[3])) l = m+1;
				else r = m;
			}
			--l;
			ans = tab[l-1];
			printf("%d\n", ans);
		}
	}
	return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值