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开始标号。我会使用一些方式强制你在线。
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
5
170337785
271451044
22430280
969056313
206452321
3
3 1 0 2
2 3 1 4
3 1 4 0
271451044
271451044
969056313
170337785
271451044
22430280
969056313
206452321
3
3 1 0 2
2 3 1 4
3 1 4 0
271451044
271451044
969056313
Sample Output
HINT
0:n,Q<=100
1,...,5:n<=2000
0,...,19:n<=20000,Q<=25000
题解:
十分经典啊,好题,中位数的题目,以后可以想到二分去解决。
就是比中位数大的变1,小的为-1,则sum>=0即可判断是否可以比当前二分的
中位数更大,然后就可以,所以对于从小到大,开n个不同状态的线段树,这样就可以了。
1 #include<cstring> 2 #include<cmath> 3 #include<algorithm> 4 #include<iostream> 5 #include<cstdio> 6 7 #define lson tr[p].ls 8 #define rson tr[p].rs 9 #define N 20007 10 using namespace std; 11 inline int read() 12 { 13 int x=0,f=1;char ch=getchar(); 14 while(ch>'9'||ch<'0'){if (ch=='-') f=-1;ch=getchar();} 15 while(ch<='9'&&ch>='0'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();} 16 return x*f; 17 } 18 19 int n,m,sz,ans; 20 int a[N],id[N],rt[N]; 21 struct Node 22 { 23 int sum,lmx,rmx,ls,rs; 24 }tr[N*20]; 25 26 bool cmp(int x1,int x2) 27 { 28 return a[x1]<a[x2]; 29 } 30 void update(int p) 31 { 32 tr[p].sum=tr[lson].sum+tr[rson].sum; 33 tr[p].lmx=max(tr[lson].lmx,tr[lson].sum+tr[rson].lmx); 34 tr[p].rmx=max(tr[rson].rmx,tr[rson].sum+tr[lson].rmx); 35 } 36 void build(int &p,int l,int r) 37 { 38 p=++sz; 39 if (l==r) 40 { 41 tr[p].sum=tr[p].lmx=tr[p].rmx=1; 42 return; 43 } 44 int mid=(l+r)>>1; 45 build(tr[p].ls,l,mid),build(tr[p].rs,mid+1,r); 46 update(p); 47 } 48 void build_new(int yl,int l,int r,int &xz,int val,int z) 49 { 50 xz=++sz;tr[xz]=tr[yl]; 51 if (l==r) 52 { 53 tr[xz].lmx=tr[xz].rmx=tr[xz].sum=val; 54 return; 55 } 56 int mid=(l+r)>>1; 57 if (z<=mid) build_new(tr[yl].ls,l,mid,tr[xz].ls,val,z); 58 else build_new(tr[yl].rs,mid+1,r,tr[xz].rs,val,z); 59 update(xz); 60 } 61 int get_sum(int p,int l,int r,int x,int y) 62 { 63 if (l==x&&r==y) return tr[p].sum; 64 int mid=(l+r)>>1; 65 if (y<=mid) return get_sum(tr[p].ls,l,mid,x,y); 66 else if (x>mid) return get_sum(tr[p].rs,mid+1,r,x,y); 67 else return get_sum(tr[p].ls,l,mid,x,mid)+get_sum(tr[p].rs,mid+1,r,mid+1,y); 68 } 69 int get_rx(int p,int l,int r,int x,int y) 70 { 71 if (l==x&&r==y) return tr[p].lmx; 72 int mid=(l+r)>>1; 73 if (y<=mid) return get_rx(tr[p].ls,l,mid,x,y); 74 else if (x>mid) return get_rx(tr[p].rs,mid+1,r,x,y); 75 else return max(get_rx(tr[p].ls,l,mid,x,mid),get_sum(tr[p].ls,l,mid,x,mid)+get_rx(tr[p].rs,mid+1,r,mid+1,y)); 76 } 77 int get_lx(int p,int l,int r,int x,int y) 78 { 79 if (l==x&&r==y) return tr[p].rmx; 80 int mid=(l+r)>>1; 81 if (y<=mid) return get_lx(tr[p].ls,l,mid,x,y); 82 else if (x>mid) return get_lx(tr[p].rs,mid+1,r,x,y); 83 else return max(get_lx(tr[p].rs,mid+1,r,mid+1,y),get_sum(tr[p].rs,mid+1,r,mid+1,y)+get_lx(tr[p].ls,l,mid,x,mid)); 84 } 85 bool check(int k,int a,int b,int c,int d) 86 { 87 int sum=0; 88 if (b+1<=c-1) sum+=get_sum(rt[k],1,n,b+1,c-1); 89 sum+=get_lx(rt[k],1,n,a,b); 90 sum+=get_rx(rt[k],1,n,c,d); 91 return sum>=0;//大的个数多的话那么可以找更大的中位数、 92 } 93 int main() 94 { 95 n=read(); 96 for (int i=1;i<=n;i++) 97 a[i]=read(),id[i]=i; 98 sort(id+1,id+n+1,cmp); 99 build(rt[1],1,n); 100 for (int i=2;i<=n;i++) 101 build_new(rt[i-1],1,n,rt[i],-1,id[i-1]); 102 int qz[5]; 103 m=read(); 104 while(m--) 105 { 106 qz[1]=read(),qz[2]=read(),qz[3]=read(),qz[4]=read(); 107 for (int i=1;i<=4;i++) 108 qz[i]=(qz[i]+ans)%n; 109 for (int i=1;i<=4;i++) 110 qz[i]+=1; 111 sort(qz+1,qz+4+1); 112 int l=1,r=n,mid; 113 while(l<r) 114 { 115 mid=(l+r+1)>>1; 116 if (check(mid,qz[1],qz[2],qz[3],qz[4])) l=mid; 117 else r=mid-1; 118 } 119 ans=a[id[l]]; 120 printf("%d\n",ans); 121 } 122 }