[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;
    
}

 

posted @ 2019-03-29 20:30  evenbao  阅读(154)  评论(0编辑  收藏  举报