[国家集训队]middle 解题报告
[国家集训队]middle
主席树的想法感觉挺妙的,但是这题数据范围这么小,直接分块草过去不就好了吗
二分是要二分的,把\(<x\)置\(-1\),\(\ge x\)的置\(1\),于是我们需要取一个\(\ge 0\)的区间
对询问\(a,b,c,d\),其中\([b,c]\)是必选的,\([a,b-1]\)取后缀最大和,\([c+1,d]\)取前缀最大和
我们直接分块,对每个块的每个答案\(x\)维护一个块内和,前缀最大和和后缀最大和就可以了
然后询问的时候暴力跳块就好了
复杂度\(O(n\sqrt n+n\sqrt n \log n)\)
Code:
#include <cstdio>
#include <cctype>
#include <cmath>
#include <cstring>
#include <algorithm>
const int N=30010;
using std::min;
using std::max;
template <class T>
void read(T &x)
{
x=0;char c=getchar();
while(!isdigit(c)) c=getchar();
while(isdigit(c)) x=x*10+c-'0',c=getchar();
}
int yuul[200][N],yuur[200][N],bee[200][N],belong[N];
int a[N],b[N],L[200],R[200],qry[5],n,m,q;
int cal(int l,int r,int x)
{
int lp=belong[l],rp=belong[r],ret=0;
if(rp-lp<=1)
{
for(int i=l;i<=r;i++) ret+=a[i]<x?-1:1;
return ret;
}
for(int i=l;i<=R[lp];i++) ret+=a[i]<x?-1:1;
for(int i=L[rp];i<=r;i++) ret+=a[i]<x?-1:1;
for(int i=lp+1;i<rp;i++) ret+=bee[i][x];
return ret;
}
int rig(int l,int r,int x)
{
if(l>r) return 0;
int lp=belong[l],rp=belong[r],sum=0,mx=0;
if(rp-lp<=1)
{
for(int i=l;i<=r;i++)
{
sum+=a[i]<x?-1:1;
mx=max(mx,sum);
}
return mx;
}
for(int i=l;i<=R[lp];i++)
{
sum+=a[i]<x?-1:1;
mx=max(mx,sum);
}
for(int i=lp+1;i<rp;i++)
{
mx=max(mx,sum+yuul[i][x]);
sum+=bee[i][x];
}
for(int i=L[rp];i<=r;i++)
{
sum+=a[i]<x?-1:1;
mx=max(mx,sum);
}
return mx;
}
int lef(int l,int r,int x)
{
if(l>r) return 0;
int lp=belong[l],rp=belong[r],sum=0,mx=0;
if(rp-lp<=1)
{
for(int i=r;i>=l;i--)
{
sum+=a[i]<x?-1:1;
mx=max(sum,mx);
}
return mx;
}
for(int i=r;i>=L[rp];i--)
{
sum+=a[i]<x?-1:1;
mx=max(sum,mx);
}
for(int i=rp-1;i>lp;i--)
{
mx=max(mx,sum+yuur[i][x]);
sum+=bee[i][x];
}
for(int i=R[lp];i>=l;i--)
{
sum+=a[i]<x?-1:1;
mx=max(sum,mx);
}
return mx;
}
bool check(int a,int b,int c,int d,int x)
{
return lef(a,b-1,x)+cal(b,c,x)+rig(c+1,d,x)>=0;
}
int query(int a,int b,int c,int d)
{
int l=1,r=m;
while(l<r)
{
int mid=l+r+1>>1;
if(check(a,b,c,d,mid)) l=mid;
else r=mid-1;
}
return l;
}
int main()
{
memset(bee,-0x3f,sizeof bee);
memset(yuul,-0x3f,sizeof yuul);
memset(yuur,-0x3f,sizeof yuur);
read(n);
for(int i=1;i<=n;i++) read(a[i]),b[i]=a[i];
std::sort(b+1,b+1+n);
m=std::unique(b+1,b+1+n)-b-1;
for(int i=1;i<=n;i++) a[i]=std::lower_bound(b+1,b+1+m,a[i])-b;
int B=sqrt(n)+1,T=(n-1)/B+1;
for(int i=1;i<=T;i++)
{
L[i]=R[i-1]+1,R[i]=min(L[i]+B-1,n);
for(int j=L[i];j<=R[i];j++)
{
belong[j]=i;
int sum=0,mx=0,x=a[j];
for(int k=L[i];k<=R[i];k++)
{
sum+=a[k]<x?-1:1;
mx=max(mx,sum);
}
yuul[i][x]=mx;
sum=0,mx=0;
for(int k=R[i];k>=L[i];k--)
{
sum+=a[k]<x?-1:1;
mx=max(mx,sum);
}
yuur[i][x]=mx;
bee[i][x]=sum;
}
bee[i][m+1]=yuul[i][m+1]=yuur[i][m+1]=-B;
for(int j=m;j;j--)
{
bee[i][j]=max(bee[i][j],bee[i][j+1]);
yuul[i][j]=max(yuul[i][j],yuul[i][j+1]);
yuur[i][j]=max(yuur[i][j],yuur[i][j+1]);
}
}
read(q);
for(int las=0,i=1;i<=q;i++)
{
for(int j=1;j<=4;j++)
{
read(qry[j]);
qry[j]=(qry[j]+las)%n+1;
}
std::sort(qry+1,qry+5);
printf("%d\n",las=b[query(qry[1],qry[2],qry[3],qry[4])]);
}
return 0;
}
2019.3.17
[国家集训队]middle 解题报告的更多相关文章
- 洛谷 P1505 [国家集训队]旅游 解题报告
P1505 [国家集训队]旅游 题目描述 \(\tt{Ray}\) 乐忠于旅游,这次他来到了\(T\)城.\(T\)城是一个水上城市,一共有 \(N\) 个景点,有些景点之间会用一座桥连接.为了方便游 ...
- [国家集训队]middle
[国家集训队]middle 题目 解法 开\(n\)颗线段树,将第\(i\)颗线段树中大于等于第\(i\)小的数权值赋为1,其他的则为-1,对于每个区间维护一个区间和,最大前缀和,最大后缀和. 然后二 ...
- P2839 [国家集训队]middle
P2839 [国家集训队]middle 好妙的题啊,,,, 首先二分一个答案k,把数列里>=k的数置为1,=0就是k>=中位数,<0就是k<中位数 数列的最大和很好求哇 左边的 ...
- CF484E Sign on Fence && [国家集训队]middle
CF484E Sign on Fence #include<bits/stdc++.h> #define RG register #define IL inline #define _ 1 ...
- 【LG2839】[国家集训队]middle
[LG2839][国家集训队]middle 题面 洛谷 题解 按照求中位数的套路,我们二分答案\(mid\),将大于等于\(mid\)的数设为\(1\),否则为\(-1\). 若一个区间和大于等于\( ...
- 解题:国家集训队 Middle
题面 求中位数的套路:二分,大于等于的设为1,小于的设为-1 于是可以从小到大排序后依次加入可持久化线段树,这样每次只会变化一个位置 那左右端点是区间怎么办? 先把中间的算上,然后维护每个区间左右两侧 ...
- BZOJ.2653.[国家集训队]middle(可持久化线段树 二分)
BZOJ 洛谷 求中位数除了\(sort\)还有什么方法?二分一个数\(x\),把\(<x\)的数全设成\(-1\),\(\geq x\)的数设成\(1\),判断序列和是否非负. 对于询问\(( ...
- luogu2839 [国家集训队]middle
题目链接:洛谷 题目大意:给定一个长度为$n$的序列,每次询问左端点在$[a,b]$,右端点在$[c,d]$的所有子区间的中位数的最大值.(强制在线) 这里的中位数定义为,对于一个长度为$n$的序列排 ...
- [洛谷P2839][国家集训队]middle
题目大意:给你一个长度为$n$的序列$s$.$Q$个询问,问在$s$中的左端点在$[a,b]$之间,右端点在$[c,d]$之间的子段中,最大的中位数. 强制在线. 题解:区间中位数?二分答案,如果询问 ...
随机推荐
- asp.net mvc area实现多级controller和多级view
经常需要描述这样的项目结构 ~:. //web根目录├─.admin //管理员功能目录│ └─index.html //管理员目录页面├─.user / ...
- Composer之搭建自己的包工具
作为一个标准的PHPer,必须学会优雅的使用composer,最近,萌生了一个想法,我们每搭建一个项目,里面都会有许多的公用的方法和类库,每次使用的时候就是将其拷贝过来,或者重新写一遍,过于繁琐,效率 ...
- PostgreSQL 安装了contrib 之后 登录失败的问题
1. 自己之前只是安装了 pg 10.6 2. 开发同事 需要用到 一个extensions 叫做 uuid-ossp 3. 执行报错 详情见昨天的blog 4. 然后执行了升级操作 结果 pg10 ...
- golang操作mysql使用总结
前言 Golang 提供了database/sql包用于对SQL数据库的访问, 作为操作数据库的入口对象sql.DB, 主要为我们提供了两个重要的功能: sql.DB 通过数据库驱动为我们提供管理底层 ...
- linux下编译tex,bib成pdf文件
参考linux下编译bib.tex生成pdf文件 为了编译出出正确的pdf文件,需要执行4条命令完成整个编译过程. 编译命令及输出 $ pdflatex bb.tex #目录下会生成bb.aux.bb ...
- 极验3.0滑动拼图验证的使用--java
[ 前言: 在登录其他网站的时候,看到有个滑动拼图的验证觉得挺好玩的,以前做一个图片验证的小demo,现在发现很多网站都开始流行滑动拼图的验证了,今天也想自己动手来弄一个. 废话不多说,开始撸起来! ...
- 4.请介绍一下c++和Java的区别
1.指针 2.c++多重继承,Java只能继承一个父类,但是可以继承多个接口 3.数据类型及类,Java完全面向对象,所有函数和变量都必须是类的一部分.而c++允许将函数和变量定义为全局,Java取消 ...
- Python之路-(Django(csrf,中间件,缓存,信号,Model操作,Form操作))
csrf 中间件 缓存 信号 Model操作 Form操作 csrf: 用 django 有多久,我跟 csrf 这个概念打交道就有久了. 每次初始化一个项目时都能看到 django.middlewa ...
- Quartz 定时任务时间设置
转自https://blog.csdn.net/zdx1515888659/article/details/79158169 quartz定时任务时间设置: 这些星号由左到右按顺序代表 : * * * ...
- 记一次ntp反射放大ddos攻击
2018/3/26 ,共计310G左右的DDoS攻击 临时解决办法:将web服务转移到同生产一个内网段的备份服务器a上,a提供web端口80,数据库通过内网连接还是沿用生产数据库. 后续解决办法:通过 ...