BZOJ 2653 middle | 主席树

题目:

http://www.lydsy.com/JudgeOnline/problem.php?id=2653



题解:

设答案为ans,把大于等于ans的记为1,小于的记为-1,这样可以知道当前ans是大了还是小了

然后二分答案,就是求最大子段和的问题,根据网上的题解:[b,c]是必选的,然后选[a,b]和[c,d]的最大字段和就行了

#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 20010
using namespace std;
int sz,q,root[N],ls[N*20],rs[N*20],sum[N*20],lm[N*20],rm[N*20],n,m,b[5],lastans;
struct node
{
    int p,v;
}a[N];
bool cmp(node a,node b)
{
    return a.v<b.v;
}
void update(int k)
{
    sum[k]=sum[ls[k]]+sum[rs[k]];
    lm[k]=max(lm[ls[k]],sum[ls[k]]+lm[rs[k]]);
    rm[k]=max(rm[rs[k]],sum[rs[k]]+rm[ls[k]]);
}
void build(int &rt,int l,int r)
{
    rt=++sz;
    int mid=l+r>>1;
    if (l==r)
    {
        sum[rt]=lm[rt]=rm[rt]=1;
        return;
    }
    build(ls[rt],l,mid);
    build(rs[rt],mid+1,r);
    update(rt);
}
void insert(int x,int l,int r,int &y,int p,int v)
{
    y=++sz;
    ls[y]=ls[x];
    rs[y]=rs[x];
    if (l==r)
    {
        sum[y]=lm[y]=rm[y]=v;
        return;
    }
    int mid=(l+r)>>1;
    if (p<=mid) insert(ls[x],l,mid,ls[y],p,v);
    else insert(rs[x],mid+1,r,rs[y],p,v);
    update(y);
}
int que1(int k,int l,int r,int ll,int rr)
{
    if (ll==l&&r==rr) return sum[k];
    int mid=(l+r)>>1;
    if (rr<=mid) return que1(ls[k],l,mid,ll,rr);
    else if (ll>mid) return que1(rs[k],mid+1,r,ll,rr);
    else return que1(ls[k],l,mid,ll,mid)+que1(rs[k],mid+1,r,mid+1,rr);
}
int que2(int k,int l,int r,int ll,int rr)
{
    if (ll==l&&r==rr) return rm[k];
    int mid=(l+r)>>1;
    if (rr<=mid) return que2(ls[k],l,mid,ll,rr);
    else if (ll>mid) return que2(rs[k],mid+1,r,ll,rr);
    else return max(que2(rs[k],mid+1,r,mid+1,rr),que1(rs[k],mid+1,r,mid+1,rr)+que2(ls[k],l,mid,ll,mid));
}
int que3(int k,int l,int r,int ll,int rr)
{
    if (ll==l&&r==rr) return lm[k];
    int mid=(l+r)>>1;
    if (rr<=mid) return que3(ls[k],l,mid,ll,rr);
    else if (ll>mid) return que3(rs[k],mid+1,r,ll,rr);
    else return max(que3(ls[k],l,mid,ll,mid),que1(ls[k],l,mid,ll,mid)+que3(rs[k],mid+1,r,mid+1,rr));
}
bool judge(int k,int a,int b,int c,int d)
{
    int temp(0);
    if (c-1>b) temp+=que1(root[k],0,n-1,b+1,c-1);
    temp+=que2(root[k],0,n-1,a,b);
    temp+=que3(root[k],0,n-1,c,d);
    return temp>=0;
}
int main()
{
    scanf("%d",&n);
    for (int i=0; i<n; i++)
    {
        scanf("%d",&a[i].v);
        a[i].p=i;
    }
    sort(a,a+n,cmp);
    build(root[0],0,n-1);
    for (int i=1; i<n; i++)insert(root[i-1],0,n-1,root[i],a[i-1].p,-1);
    scanf("%d",&q);
    for (int i=1; i<=q; i++)
    {
        scanf("%d%d%d%d",&b[0],&b[1],&b[2],&b[3]);
        for (int j=0; j<4; j++) b[j]=(b[j]+lastans)%n;
        sort(b,b+4);
        int l=0,r=n-1,x;
        while (l<=r)
        {
            int mid=(l+r)>>1;
            if (judge(mid,b[0],b[1],b[2],b[3])) x=mid,l=mid+1;
            else r=mid-1;
        }
        lastans=a[x].v;
        printf("%d\n",lastans);
    }
}

原文地址:https://www.cnblogs.com/mrsheep/p/8167795.html

时间: 2024-10-08 08:52:59

BZOJ 2653 middle | 主席树的相关文章

bzoj 2653 middle (主席树+二分)

版权声明:本文为博主原创文章,未经博主允许不得转载. bzoj 2653 题意: 一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整. 给你一个长度为n的序列s. 回答Q个这样的询问:s的左端点在[a,b]之间,右端点在[c,d]之间的子序列中,最大的中位数. 其中a<b<c<d. 位置也从0开始标号. 强制在线. 解法: 首先可以想到的是二分答案,再判断是否满足条件 . 对于答案x,我们将原数组中大于等于x的数记1,小于的记为-1,

BZOJ 2653: middle [主席树 中位数]

传送门 题意: 一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整.给你一个 长度为n的序列s.回答Q个这样的询问:s的左端点在[a,b]之间,右端点在[c,d]之间的子序列中,最大的中位数. 我会使用一些方式强制你在线. 最后一句话太可怕了$QAQ$ 首先需要知道怎么求中位数: 二分答案,$\ge$的为$1$,$<$的为$-1$,如果和$\ge 0$说明当前答案$\le$中位数 最大中位数?$GSS$! 只要求$[a,b].rm+(b,c)

BZOJ 2653: middle

2653: middle Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1536  Solved: 855[Submit][Status][Discuss] Description 一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整. 给你一个长度为n的序列s. 回答Q个这样的询问:s的左端点在[a,b]之间,右端点在[c,d]之间的子序列中,最大的中位数. 其中a<b<c<d. 位置

BZOJ 2735: 世博会 主席树+切比雪夫距离转曼哈顿距离

2735: 世博会 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 124  Solved: 51[Submit][Status][Discuss] Description 四年一度的世博会又要举办了,Q国很荣幸成为了这次世博会的主办方.Q国主席QQ从全国各地收集了N件物品排成 一排,作为Q国馆的展出物.对于相邻摆放的一些物品,如果过于相似会让人觉得无聊,如果差别过大又会让人觉 得突兀.为了让人们对这次世博会的展出满意,QQ需要知道一些相邻物品的“

Luogu2839 Middle 主席树、二分答案

题目传送门:https://www.luogu.org/problemnew/show/P2839 题目大意:给出一个长度为$N$的序列与$Q$次询问,每次询问左端点在$[a,b]$,右端点在$[c,d]$的区间中最大的中位数,强制在线(本题中的中位数定义与平常不同,设某区间长度为$L$,则在从小到大排序后的序列中(编号从$0$开始),其中位数为第$\lfloor L/2 \rfloor$号元素)$N,Q \leq 2 \times 10^4$ 这鬼题让我知道主席树可以用于除第$K$大以外的问题

bzoj 3653 谈笑风生——主席树

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3653 原来一直想怎么线段树合并.可是不会把角标挪一位. 查询的其实是子树内一段深度的点的 siz 和.因为是子树内,所以按 dfs 序建立主席树,角标是 dep ,值是 siz . 注意 long long .而且数组 *19 就会 RE ,*20就好了.不知为何. #include<iostream> #include<cstdio> #include<cstring

bzoj 2653 middle (可持久化线段树)

middle Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1981  Solved: 1097[Submit][Status][Discuss] Description 一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整.给你一个 长度为n的序列s.回答Q个这样的询问:s的左端点在[a,b]之间,右端点在[c,d]之间的子序列中,最大的中位数. 其中a<b<c<d.位置也从0开始标号

BZOJ 2653 middle 二分答案+可持久化线段树

题目大意:给定一个长度为n的序列,求当子序列s的左端点在[a,b],右端点在[c,d]时的最大中位数 其中当序列长度为偶数时中位数定义为中间两个数中较大的那个 很难想的一道题 具体题解见 http://blog.csdn.net/acm_cxlove/article/details/8566093 说的很详细 区间处理那里 [b,c]是必选的 [a,b)和(c,d]每段取最大加和 否则re恒>=0 #include<cstdio> #include<cstring> #inc

BZOJ 2653 middle 题解

题意:一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整. 给一个序列,并进行一些询问.每次询问起点在[a,b],终点在[c,d]的序列的中位数. 题解:首先有一个思路:对于一个序列S,假设它的中位数是m,则S中>=m的元素个数一定>=n 那么对于一个序列S和一个数m,我们将>=m的元素设置为1,其余为-1,得到一个新数列S‘.则$\sum S'$ >=0 对于每个询问我们二分一下m即可.如果在区间[a,d]内有一段包含[b,c