【主席树】BZOJ 2653 middle
2016-01-12 19:47
344 查看
BZOJ 2653 middle
Description
一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整。给你一个长度为n的序列s。
回答Q个这样的询问:s的左端点在[a,b]之间,右端点在[c,d]之间的子序列中,最大的中位数。
其中a < b< c < d。
位置也从0开始标号。
我会使用一些方式强制你在线。
Input
第一行序列长度n。接下来n行按顺序给出a中的数。
接下来一行Q。
然后Q行每行a,b,c,d,我们令上个询问的答案是x(如果这是第一个询问则x=0)。
令数组q={(a+x)%n,(b+x)%n,(c+x)%n,(d+x)%n}。
将q从小到大排序之后,令真正的要询问的a=q[0],b=q[1],c=q[2],d=q[3]。
输入保证满足条件。
Output
Q行依次给出询问的答案。Sample Input
5170337785
271451044
22430280
969056313
206452321
3
3 1 0 2
2 3 1 4
3 1 4 0
Sample Output
271451044271451044
969056313
HINT
0:n,Q<=1001,…,5:n<=2000
0,…,19:n<=20000,Q<=25000
Solution
口胡了一个算法不对。。只能去看题解
算法很巧妙
对于一个x,比它大的权值设为1,小的权值设为-1.
然后树一路建过去
询问的时候先二分答案
然后判定可行性
求区间最大子段和,大于0则可行
维护一下lx,rx就可以了
Code
#include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; #define maxn 20001 struct ha{ int v,l,r,lx,rx; }t[maxn*20]; struct ope{ int v,id; }op[maxn]; int size,q[5],n,root[maxn]; bool cmp(const ope A,const ope B) { return A.v<B.v; } inline int in() { int x=0;char ch=getchar(); while(ch<'0'||ch>'9')ch=getchar(); while(ch<='9'&&ch>='0')x=x*10+ch-'0',ch=getchar(); return x; } void insert(int &poi,int l,int r,int k,int d) { t[++size]=t[poi];poi=size; t[poi].v+=d; if(l==r){ t[poi].lx=t[poi].rx=-1; return; } int mid=(l+r)>>1; if(mid>=k)insert(t[poi].l,l,mid,k,d); else insert(t[poi].r,mid+1,r,k,d); t[poi].lx=max(t[t[poi].l].lx,t[t[poi].r].lx+t[t[poi].l].v); t[poi].rx=max(t[t[poi].r].rx,t[t[poi].l].rx+t[t[poi].r].v); } int qm(int x,int l,int r,int L,int R) { if(l>L||r<R||L>R)return 0; int mid=(l+r)>>1; if(l==L&&r==R)return t[x].v; else if(mid<R && mid>=L)return qm(t[x].l,l,mid,L,mid)+qm(t[x].r,mid+1,r,mid+1,R); else if(mid<L)return qm(t[x].r,mid+1,r,L,R); else if(mid>=R)return qm(t[x].l,l,mid,L,R); } int ql(int x,int l,int r,int L,int R) { if(l>L||r<R||L>R)return -9999999; int mid=(l+r)>>1; if(l==L&&R==r)return t[x].lx; else if(mid<R && mid>=L)return max(ql(t[x].l,l,mid,L,mid),qm(t[x].l,l,mid,L,mid)+ql(t[x].r,mid+1,r,mid+1,R)); else if(mid<L)return ql(t[x].r,mid+1,r,L,R); else if(mid>=R)return ql(t[x].l,l,mid,L,R); } int qr(int x,int l,int r,int L,int R) { if(l>L||r<R||L>R)return -9999999; int mid=(l+r)>>1; if(l==L&&R==r)return t[x].rx; else if(mid<R && mid>=L)return max(qr(t[x].r,mid+1,r,mid+1,R),qm(t[x].r,mid+1,r,mid+1,R)+qr(t[x].l,l,mid,L,mid)); else if(mid<L)return qr(t[x].r,mid+1,r,L,R); else if(mid>=R)return qr(t[x].l,l,mid,L,R); } bool check(int num) { int L,R,M; L=qr(root[num],1,n,q[1],q[2]); M=qm(root[num],1,n,q[2]+1,q[3]-1); R=ql(root[num],1,n,q[3],q[4]); return L+M+R>=0; } int div2() { int l=1,r=n,an; while(l<r) { int mid=(l+r+1)>>1; if(check(mid))l=mid; else r=mid-1; } return l; } void build(int l,int r,int &k) { k=++size; t[k].v=r-l+1; if(l==r) { t[k].lx=t[k].rx=1; return; } int mid=(l+r)>>1; build(l,mid,t[k].l); build(mid+1,r,t[k].r); t[k].lx=max(t[t[k].l].lx,t[t[k].r].lx+t[t[k].l].v); t[k].rx=max(t[t[k].r].rx,t[t[k].l].rx+t[t[k].r].v); } int main() { freopen("2653.in","r",stdin); n=in(); for(int i=1;i<=n;i++) op[i].v=in(),op[i].id=i; sort(1+op,1+op+n,cmp); build(1,n,root[1]); for(int i=2;i<=n;i++) { root[i]=root[i-1]; insert(root[i],1,n,op[i-1].id,-2); } int m=in(),ans=0; for(int i=1;i<=m;i++) { for(int j=1;j<=4;j++) q[j]=(in()+ans)%n+1; sort(1+q,1+q+4); ans=op[div2()].v; printf("%d\n",ans); } return 0; }
相关文章推荐
- FaceRecognition
- 基于Socket与C的WEB页面抓取程序
- Android将程序崩溃信息保存本地文件以及上传到服务器
- 时序约束 STA
- 数组指针辨析
- c++ 使用socket实现C/S端文件的下载传输
- 一段SQL
- easyui异步
- 代码中padding的单位
- 算法学习【1】三个空汽水瓶可以换一瓶汽水
- 用caffe训练人工神经网络
- SSH Secure Shell Client 连接Linux 乱码
- 分布式消息系统Jafka入门指南之二
- Redis 性能測试
- 2015年乐学琴产品总结
- Quartz2.2.2的简单使用
- C++ socket编程 实现服务端与客户端的通讯
- POJ2125 Destroying The Graph(二分图最小点权覆盖集)
- 运算符重载
- string类--复制《copy()与copyTo()》