[BZOJ 2653] middle
[题目链接]
https://www.lydsy.com/JudgeOnline/problem.php?id=2653
[算法]
显然 , 问题具有单调性 , 不妨对于每组询问首先二分答案mid
将大于等于mid的数看作1 , 小于mid的数看作-1 , 问题转化为判断是否有左端点在[l1 , r1] , 右端点在[l2 , r2] , 区间和大于等于0的区间
那么我们只要对于每个数建立线段树 , 维护向左 , 右延伸的最大子段和
但是这样我们需要建立n棵线段树 , 显然是不可行的
不难发现 , 第i棵线段树和第(i - 1)棵线段树相比只有一个元素的值不同
将该过程可持久化即可
时间复杂度 : O(NlogN ^ 2)
[代码]
#include<bits/stdc++.h> using namespace std; #define N 20010 typedef long long ll; typedef long double ld; typedef unsigned long long ull; const int inf = 1e9; struct info { int lmax , rmax , sum; } Ans; int n , q; int a[N] , perm[N] , rt[N]; struct Presitent_Segment_Tree { int sz; int lc[N * 40] , rc[N * 40] , lm[N * 40] , rm[N * 40] , cnt[N * 40]; Presitent_Segment_Tree() { sz = 0; } inline void build(int &now , int l , int r) { now = ++sz; lm[now] = rm[now] = cnt[now] = r - l + 1; if (l == r) return; int mid = (l + r) >> 1; build(lc[now] , l , mid); build(rc[now] , mid + 1 , r); } inline void update(int now) { lm[now] = max(lm[lc[now]] , cnt[lc[now]] + lm[rc[now]]); rm[now] = max(rm[rc[now]] , cnt[rc[now]] + rm[lc[now]]); cnt[now] = cnt[lc[now]] + cnt[rc[now]]; } inline void modify(int &now , int old , int l , int r , int x , int value) { now = ++sz; lc[now] = lc[old] , rc[now] = rc[old]; if (l == r) { cnt[now] = lm[now] = rm[now] = value; return; } int mid = (l + r) >> 1; if (mid >= x) modify(lc[now] , lc[old] , l , mid , x , value); else modify(rc[now] , rc[old] , mid + 1 , r , x , value); update(now); } inline void merge(info &x , info y) { info ret; ret.lmax = max(x.lmax , x.sum + y.lmax); ret.rmax = max(y.rmax , y.sum + x.rmax); ret.sum = x.sum + y.sum; x = ret; } inline void query(int now , int l , int r , int ql , int qr) { if (l == ql && r == qr) merge(Ans , (info){lm[now] , rm[now] , cnt[now]}); else { int mid = (l + r) >> 1; if (mid >= qr) query(lc[now] , l , mid , ql , qr); else if (mid + 1 <= ql) query(rc[now] , mid + 1 , r , ql , qr); else { query(lc[now] , l , mid , ql , mid); query(rc[now] , mid + 1 , r , mid + 1 , qr); } } } } PST; template <typename T> inline void chkmax(T &x,T y) { x = max(x,y); } template <typename T> inline void chkmin(T &x,T y) { x = min(x,y); } template <typename T> inline void read(T &x) { T f = 1; x = 0; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - '0'; x *= f; } inline bool cmp(int x , int y) { return a[x] < a[y]; } inline int query(int l1 , int r1 , int l2 , int r2 , int x) { int ret = 0; Ans = (info){-inf , -inf , 0}; if (r1 + 1 <= l2 - 1) PST.query(rt[x] , 1 , n , r1 + 1 , l2 - 1); ret += Ans.sum; Ans = (info){-inf , -inf , 0}; PST.query(rt[x] , 1 , n , l1 , r1); ret += Ans.rmax; Ans = (info){-inf , -inf , 0}; PST.query(rt[x] , 1 , n , l2 , r2); ret += Ans.lmax; return ret; } int main() { read(n); for (int i = 1; i <= n; ++i) { read(a[i]); perm[i] = i; } sort(perm + 1 , perm + n + 1 , cmp); PST.build(rt[1] , 1 , n); for (int i = 2; i <= n; ++i) PST.modify(rt[i] , rt[i - 1] , 1 , n , perm[i - 1] , -1); read(q); int lastans = 0; while (q--) { int Q[4] , A , B , C , D; read(A); read(B); read(C); read(D); Q[0] = (A + lastans) % n + 1; Q[1] = (B + lastans) % n + 1; Q[2] = (C + lastans) % n + 1; Q[3] = (D + lastans) % n + 1; sort(Q , Q + 4); int l = 1 , r = n , ans = 0; while (l <= r) { int mid = (l + r) >> 1; if (query(Q[0] , Q[1] , Q[2] , Q[3] , mid) >= 0) { ans = a[perm[mid]]; l = mid + 1; } else r = mid - 1; } printf("%d\n" , lastans = ans); } return 0; }