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

middle

Time Limit: 20 Sec  Memory Limit: 512 MB
Submit: 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

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 }

 

posted @ 2017-12-18 20:02  Kaiser-  阅读(196)  评论(0编辑  收藏  举报